So my problem is that i want after double click on item in RecyclerView adapter to trigger the animation on ImageView. I detect the double tap in adapter, take the coordinates of the tapped area in format of int[] location, call the method in Fragment passing the location.
public void performAnimation(int[] location) {
ImageView imageView = new ImageView(getContext());
imageView.setImageDrawable(getActivity().getDrawable(R.drawable.ic_imageview));
ConstraintLayout.LayoutParams params =
new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, location[0], 0, location[1]);
imageView.setLayoutParams(params);
parentViewGroup2.addView(imageView);
ObjectAnimator translateAnim = ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, 0.5f);
translateAnim.setDuration(2000);
translateAnim.start();
So the problem is that i only get to draw the image in layout, but animation wont start. I have also tryed that with TransitionManager with beginDelayedTransition, but again, nothing. Does anyone have any idea what am i doing wrong? Thanks in advance.
ObjectAnimator.ofFloat receives an array of float values of which value the animation will run through, you only pass 1 0.5f param which is not enough. Also, the float here should be an absolute pixel on the screen will be translated, not an offset value.
Try this ViewPropertyAnimator instead:
imageView.animate().translationY(400).setDuration(200).start();
Related
What I want to do is simultaneously scale and translate an ImageView based when the user touches is. The final position and size of the ImageView should be equal to the target.
Below is a snipper of the OnClickListener attached to every ImageView that should perform this action. The new position and size is obtained from ivYou, which also is an ImageView.
#Override
public void onClick(View v) {
// Create animations
int[] from = new int[2];
int[] to = new int[2];
//v.getLocationInWindow(from);
v.getLocationOnScreen(from);
//ivYou.getLocationInWindow(to);
ivYou.getLocationOnScreen(to);
TranslateAnimation transAnim = new TranslateAnimation(0, to[0] - from[0], 0, to[1] - from[0]);
float factorX = ivYou.getWidth() / v.getWidth();
float factorY = ivYou.getHeight() / v.getHeight();
ScaleAnimation scaleAnim = new ScaleAnimation(1.0f, factorX, 1.0f, factorY);
// Create animation set
AnimationSet set = new AnimationSet(true);
set.setFillAfter(true);
set.setDuration(ANIM_DURATION);
set.addAnimation(transAnim);
set.addAnimation(scaleAnim);
// Start animations and disable click listener
v.startAnimation(set);
v.setOnClickListener(null);
}
ANIM_DURATION is 2000 miliseconds.
When I run this code the strangest things happen. The ImageView turns half a circle and gets smaller then its supposed to be. When I do not add the ScaleAnimator to the animation set, then the ImageView is moved to the new position. However, this new position isn't the same for every ImageView. Note that the ImageView's with this OnClickListener all have a different initial position.
Any help and feedback is greatly appreciated!
I was able to achieve this animation by wrapping the target View in a layout group and animating them separately.
In other words, I translate the wrapper layout, and scale the child view. Translating and scaling the same view at the same time always seems to result in unexpected animation trajectories as the scaling messes with the coordinate system the translate animation is using.
translateTarget.animate().x(deltaX).y(deltaY).setDuration(1000);
scaleTarget.animate().scaleX(0.01f).scaleY(0.01f).setDuration(1000)
Did you try this constructor?
ScaleAnimation (float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) and have pivotX be widthofimageview/2 and pivotY be the heightofimageview/2 for it to be the center. This is what I used in my translate scale animation.
In a RelativeLayout, I added an ImageView with some margin set in LayoutParams:
RelativeLayout.LayoutParams rlLayoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
rlLayoutParams.topMargin = (int) convertDpToPixel(kMARGIN_HEADER);
rlLayoutParams.leftMargin = (int) myMAGIC_MARGIN;
Now this ImageView is somewhere in the middle of the screen. I want to have it slide a few hundred pixels to its right, and stay there, so I applied the following TranslateAnimation:
private TranslateAnimation getAnimation(ImageView view, int displacement, int duration) {
int[] view_pos = new int[2];
view.getLocationOnScreen(view_pos);
TranslateAnimation slide = new TranslateAnimation(
view_pos[0],
view_pos[0] + displacement,
view_pos[1],
view_pos[1]);
slide.setFillAfter(true);
slide.setDuration(duration);
return slide;
}
Immediately after applying this animation, the whole view is gone. I checked the value of view_pos[] in debug mode, they are fine (not all zeroes). If I make the setFillAfter to false, then the view will come back after animation duration (for obvious reasons). So where did it go?
I also tried the following:
TranslateAnimation slide = new TranslateAnimation(
view_pos[0],
view_pos[0], // don't do the + displacement,
view_pos[1],
view_pos[1]);
I was expecting the view to stay where it is. But no, it was vanished as well, with a chance of coming back afterwards, depending on the value of setFillAfter.
I start to think I cannot apply TranslateAnimation if the view was placed by LayoutParams in a RelativeLayout. How should I achieve the goal of sliding the view?
The parameters for TranslateAnimation are deltas not positions, so you just want:
slide = new TranslateAnimation(0, displacement, 0, 0).
If you don't need to support Android <3.0 then use a Property Animation instead of a View Animation - see the Android docs for more details.
I need to make a textview that perform an animation from top to bottom and the animation start with the y value 50. How to do it? Thanks in advance.
You can use TranslateAnimation.
TranslateAnimation uses deltas, so to calculate the position of 50px from the top of the screen, subtract the top of the view & add 50.
In this example, I set the toY by adding some value to the fromY.
Here's the code:
int fromY = 50 - view.getTop();
int toY = fromY + someValue;
TranslateAnimation animation = new TranslateAnimation(0, 0, fromY, toY);
animation.setDuration(someDuration);
view.startAnimation(animation);
Hope this helps :)
I want to have myView move deltaX, deltaY pixels from current position.
But it moves two times longer than I want.
This is caused by setLayoutParams in onAnimationEnd.
Without that, myView's real positon is not changed.
How can I change myView's real positon and animate normally?
class MyLayout extends RelativeLayout {
Animation animation;
MyView myView;
animation = new TranslateAnimation(0, deltaX, 0, deltaY);
animation.setDuration(100);
animation.setFillAfter(true);
myView.startAnimation(animation);
}
class MyView extends ImageView {
protected void onAnimationEnd() {
super.onAnimationEnd();
LayoutParams params = (LayoutParams)getLayoutParams();
params.leftMargin += deltaX;
params.topMargin += deltaY;
setLayoutParams(params);
}
}
If you want to avoid doing the desired translation of the view twice as you are doing it now, you have to set the "setFillAfter" flag for the animation to false. As the documentation says "When setFillAfter is set to true, the animation transformation is applied after the animation is over."
On the other hand if you leave the "setFillAfter" flag to true, the view should translate to the desired location and no LayoutParams modification is needed in onAnimationEnd method. So it might be that something is blocking the transformation, if you could provide further information about the layout that the view is part of, it would be mostly helpful.
Another thing is that setting the margin of the layout params to move the view is not entirely the best idea. Take it more like a hack. Rather try to set the position of the view directly or try to play with weights in your parent view. That way you will get the same effect on multiple different screens.
I have a button that I want to put on a 45 degree angle. For some reason I can't get this to work.
Can someone please provide the code to accomplish this?
API 11 added a setRotation() method to all views.
You could create an animation and apply it to your button view. For example:
// Locate view
ImageView diskView = (ImageView) findViewById(R.id.imageView3);
// Create an animation instance
Animation an = new RotateAnimation(0.0f, 360.0f, pivotX, pivotY);
// Set the animation's parameters
an.setDuration(10000); // duration in ms
an.setRepeatCount(0); // -1 = infinite repeated
an.setRepeatMode(Animation.REVERSE); // reverses each repeat
an.setFillAfter(true); // keep rotation after animation
// Aply animation to image view
diskView.setAnimation(an);
Extend the TextView class and override the onDraw() method. Make sure the parent view is large enough to handle the rotated button without clipping it.
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.rotate(45,<appropriate x pivot value>,<appropriate y pivot value>);
super.onDraw(canvas);
canvas.restore();
}
I just used the simple line in my code and it works :
myCusstomView.setRotation(45);
Hope it works for you.
One line in XML
<View
android:rotation="45"
... />
Applying a rotation animation (without duration, thus no animation effect) is a simpler solution than either calling View.setRotation() or override View.onDraw method.
// substitude deltaDegrees for whatever you want
RotateAnimation rotate = new RotateAnimation(0f, deltaDegrees,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
// prevents View from restoring to original direction.
rotate.setFillAfter(true);
someButton.startAnimation(rotate);
Rotating view with rotate() will not affect your view's measured size. As result, rotated view be clipped or not fit into the parent layout. This library fixes it though:
https://github.com/rongi/rotate-layout
Joininig #Rudi's and #Pete's answers. I have created an RotateAnimation that keeps buttons functionality also after rotation.
setRotation() method preserves buttons functionality.
Code Sample:
Animation an = new RotateAnimation(0.0f, 180.0f, mainLayout.getWidth()/2, mainLayout.getHeight()/2);
an.setDuration(1000);
an.setRepeatCount(0);
an.setFillAfter(false); // DO NOT keep rotation after animation
an.setFillEnabled(true); // Make smooth ending of Animation
an.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
mainLayout.setRotation(180.0f); // Make instant rotation when Animation is finished
}
});
mainLayout.startAnimation(an);
mainLayout is a (LinearLayout) field
As mentioned before, the easiest way it to use rotation available since API 11:
android:rotation="90" // in XML layout
view.rotation = 90f // programatically
You can also change pivot of rotation, which is by default set to center of the view. This needs to be changed programatically:
// top left
view.pivotX = 0f
view.pivotY = 0f
// bottom right
view.pivotX = width.toFloat()
view.pivotY = height.toFloat()
...
In Activity's onCreate() or Fragment's onCreateView(...) width and height are equal to 0, because the view wasn't measured yet. You can access it simply by using doOnPreDraw extension from Android KTX, i.e.:
view.apply {
doOnPreDraw {
pivotX = width.toFloat()
pivotY = height.toFloat()
}
}
if you wish to make it dynamically with an animation:
view.animate()
.rotation(180)
.start();
THATS IT
#Ichorus's answer is correct for views, but if you want to draw rotated rectangles or text, you can do the following in your onDraw (or onDispatchDraw) callback for your view:
(note that theta is the angle from the x axis of the desired rotation, pivot is the Point that represents the point around which we want the rectangle to rotate, and horizontalRect is the rect's position "before" it was rotated)
canvas.save();
canvas.rotate(theta, pivot.x, pivot.y);
canvas.drawRect(horizontalRect, paint);
canvas.restore();
fun rotateArrow(view: View): Boolean {
return if (view.rotation == 0F) {
view.animate().setDuration(200).rotation(180F)
true
} else {
view.animate().setDuration(200).rotation(0F)
false
}
}
That's simple,
in Java
your_component.setRotation(15);
or
your_component.setRotation(295.18f);
in XML
<Button android:rotation="15" />