Rotating a view in Android - android

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" />

Related

Reset view to original position after animation

I'm animating a view and I want to reset the view to the original position after animation ended.
This is what I have:
rl2 is a relativeLayout
rl2.animate().translationX(-60).translationY(117).setDuration(2000);
I tried setting this but its not working:
rl2.clearAnimation();
clearAnimation(); does not reset your animations, it just stops them and removes them from the animation queue. To undo your animations you need to actually undo them. So, for your code block you will need to call rl2.animate().translationX(0).translationY(0).setDuration(2000); to move the view back to its original position.
As #Chris Stillwell mentioned on his answer, But you can move View back to it's original position after translation animation by
rl2.animate().translationX(0).translationY(0);
I know this question was asked long time ago but someone may still look for answer.
I use the Animation class for this kind of thing; there is a setFillAfter method in this class, so you can set if you want the animation to apply its transformation after it ends.
Animation anim = new ScaleAnimation(
1f, 1f, // Start and end values for the X axis scaling
1f, 2f, // Start and end values for the Y axis scaling
Animation.RELATIVE_TO_SELF, 0f, // Pivot point of X scaling
Animation.RELATIVE_TO_SELF, 1f); // Pivot point of Y scaling
anim.setFillAfter(false); // no needed to keep the result of the animation
anim.setDuration(1000);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
gangsterImage.startAnimation(anim);
If you're going to remove view don't use animation.removeAllListeners(), the function cannot continue that's why you will see some error. If you want to disappear a view, use View.GONE
in Kotlin like this:
animation.doOnEnd {
binding.mainLayout.visibility = View.GONE}
But by this way you couldn't remove any animation! So it' better rest them to the initial position.
binding.tvM2.animate().translationX(0f).translationY(0f).rotation(0f)
just use anim.setFillAfter(false); to reset automatically after animation ends.

How To Change pivot and set to Center in yoyo lib Animation

I have a problem with yoyo lib. when I run the project, Animation Rotate from top-left corner. I want change .pivot() and set to center pivot.
in fact I want Animation Rotation on the center pivot, as like Rotation Ball.
But I don't know how to change code.
Thanks for help.
My Code:
YoYo.with(Techniques.RotateIn)
.duration(2000)
.pivot(float pivotX, float pivotY) //How to set parameters this line code?
.playOn(my_view);
The default pivot is:
.pivot(YoYo.CENTER_PIVOT, YoYo.CENTER_PIVOT)
You can add a GlobalLayoutListener if your view is not loaded completely:
yourView.getViewTreeObserver().addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
YoYo.with(Techniques.RotateIn)
.duration(2000)
.pivot(YoYo.CENTER_PIVOT, YoYo.CENTER_PIVOT)
.playOn(yourView);
}
});

How to move a view to another view using animation in Android?

I have a circle at the center of the screen inside which there's an ImageView + TextView. I have another two ImageView+TextView, one at the top and another at bottom of the screen.
My requirement is :
I want a copy of the top ImageView+TextView and a copy of the bottom ImageView+TextView to move in animation into the center of the circle, thereby changing the value of the textView inside the circle.
For example:
Say top textView has value 200 and bottom textview has value 300. I want a portion of those values (say 100 or 150) to animate and move into the circle, but the original values 200 and 300 should remain on the same position.
I've tried using TranslateAnimation. However I face issues finding the x and y coordinates of the center circle. It is not exactly going to the center of the circle. Also original view's position is not retained.
TranslateAnimation animation = new
TranslateAnimation(startLayout.getX(),endLayout.getX(),
startLayout.getY(),endLayout.getY);
animation.setDuration(1000);
animation.setFillAfter(false);
startView.startAnimation(animation);
startLayout is the linearlayout in which ImageView and TextView reside.
Please help! Thanks!
I had the same issue and I fixed by using the next code (sorry is in Kotlin, but works the same in Java).Let's say viewFirst wants to reach viewTwo position:
(DON'T USE):
viewFirst.animate()
.translationX(viewSecond.x)
.translationY(viewSecond.y)
.setDuration(1000)
.withEndAction {
//to make sure that it arrives,
//but not needed actually these two lines
viewFirst.x = viewSecond.x
viewFirst.y = viewSecond.y
}
.start()
(USE THIS SOLUTION):
viewFirst.animate()
.x(viewSecond.x)
.y(viewSecond.y)
.setDuration(1000)
.withEndAction {
//to make sure that it arrives,
//but not needed actually these two lines
viewFirst.x = viewSecond.x
viewFirst.y = viewSecond.y
}
.start()
Using the getX() and getY() methods define the position of the view in pixels, but the constructor you use defines Float type values that must be values from 0.0f to 1.0f
TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
This is another option using the view`s position in pixels:
viewFirst.animate()
.x(viewSecond.getX())
.y(viewSecond.getY())
.setDuration(1000).withEndAction(new Runnable() {
#Override
public void run() {
viewFirst.setX(tv2.getX());
viewFirst.setY(tv2.getY());
}
}).start();
Try this for accurate coordinates
private fun moveView(viewToBeMoved: View, targetView: View) {
val targetX: Float =
targetView.x + targetView.width / 2 - viewToBeMoved.width / 2
val targetY: Float =
targetView.y + targetView.height / 2 - viewToBeMoved.height / 2
viewToBeMoved.animate()
.x(targetX)
.y(targetY)
.setDuration(2000)
.withEndAction {
targetView.visibility = View.GONE
}
.start()
}

Programmatically Translate View Pre-Honeycomb

How can I programmatically translate an arbitrary view without using an animation (android.view.animation.*)?
API 11 introduced setTranslationX and setTranslationY, setX and setY, and getMatrix—all of which can be used to accomplish what I'm looking for. I cannot seem to find an equivalent on the prior API levels, however.
The android.view.animation.TranslateAnimation uses getMatrix in its implementation (as far back as API 4) but it was a private API throughout this time.
Is there any way to accomplish this without resorting to reflection?
Favorited because I would love to be proven wrong on this one, but I ran into a similar wall when doing some Drag-n-Drop investigations awhile back.
I'm pretty sure you're stuck with offsetTopAndBottom() and offsetLeftAndRight() for moving a View around without an animation in early APIs. The big downside here is that these methods actually modify the top/bottom/left/right values, so you have to do some pretty heavy tracking if you want to go back to where you started from.
Another option would be to simply use a TranslateAnimation with a VERY short duration and set to fillAfter...
Other options require subclassing, and still aren't pretty, like translating the Canvas the View draws on. The problem here is you also have to create a parent that doesn't clip it's children so the view can draw outside its own bounds.
Yes, you can use TranslateAnimation. With fillAfter set to true your view will stay translated even after the animation ends. Here is an example:
TranslateAnimation anim=new TranslateAnimation(0, 0, 20, 20);
anim.setFillAfter(true);
anim.setDuration(0);
yourView.startAnimation(anim);
Grishka's answer helped me a lot, works perfectly. In order to animate the translation using the Honeycomb API with nineoldandroids, I set up a FloatEvaluator for the translation value and then used either setTranslationX on Honeycomb+ or the TranslateAnimation method. Here is my code:
public class TranslationXEvaluator extends FloatEvaluator {
private View view;
public TranslationXEvaluator(View view) {
this.view = view;
}
#Override
public Float evaluate(float fraction, Number startValue, Number endValue) {
float translationX = super.evaluate(fraction, startValue, endValue);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
view.setTranslationX(translationX);
} else {
TranslateAnimation anim = new TranslateAnimation(translationX, translationX, 0, 0);
anim.setFillAfter(true);
anim.setDuration(0);
view.startAnimation(anim);
}
return translationX;
}
}
I was having the same problem. I was able to achieve the translation by manipulating the layoutparams, specifically the margins, of the views I wanted to translate. You can use negative values for the margins btw.
One alternative to TranslateAnimation is to subclass a View and translate the Canvas on dispatchDraw.
Something like:
public class TranslateView extends View {
private float mTranslationX = 0;
private float mTranslationY = 0;
private boolean mWillUseSDKTranslation = true;
#Override
protected void dispatchDraw(final Canvas canvas) {
if (mWillUseSDKTranslation == false) {
// keep track of the current state
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// translate
canvas.translate(mTranslationX, mTranslationY);
// draw it
super.dispatchDraw(canvas);
// restore to the previous state
canvas.restore();
} else {
super.dispatchDraw(canvas);
}
}
public void setTranslationValue(final float aTranslationX, final float aTranslationY) {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
mWillUseSDKTranslation = false;
mTranslationX = aTranslationX;
mTranslationY = aTranslationY;
invalidate();
} else {
setTranslationX(aTranslationX);
setTranslationY(aTranslationY);
}
}
}
You also can try this code: https://github.com/BeyondAR/beyondar/blob/development/android/BeyondAR_Framework/src/com/beyondar/android/view/CustomLayout.java
Use the method setPosition.
A workaround I found was to set negative margins using:
layoutParams.setMargins(left, top, right, bottom);
yourView.setLayoutParams(layoutParams);

Android scale view

I need to scale View by setting the scale factor in percents. I need to set exactly the same param as ScaleAnimation use, because I'm going to scale it using ScaleAnimation in the future. How do I do it?
Thanks
I've solved the problem by creating animation xml file with duration=0, which sets desired parameters. It is also possible to create such animation via code. Then to apply it, just use:
Animation animationInit = AnimationUtils.loadAnimation(context, R.anim.gallery_init);
v.startAnimation(animationInit);
This will allow you to use straight up float values (percent) when handeling drawing and placements. Refer to: this lovely site which really helps with views.
public class MyView extends View {
...
#Override public void onDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale((getWidth() > getHeight()) ? getHeight() : getWidth());
// Your other code
canvas.restore();
}
...
}

Categories

Resources