I am creating an android application where each fragment is bind to a custom left to right slide animation. That i achieved using Custom Property Animation(FractionLinearLayout.java class given below). My app has several Fragment, switching among these fragment is followed by a right to left slide animation. Everything is working perfect untill i disable animation from Developer Options for testing purpose.
Nothing appears when i disable animations. I can see logcats means app is working perfect just views are not being loaded, (May be) because of the custom properties FractionTranslationX and FractionTranslationY.
Has anyone gone through this problem? Thanks in advance.
FractionLinearLayout.java: custom class for animation
public class FractionLinearLayout extends LinearLayout {
DisplayMetrics matrics = getContext().getResources().getDisplayMetrics();
public FractionLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public FractionLinearLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public FractionLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public float getFractionTranslationX() {
return getWidth() > 0 ? super.getTranslationX() / getWidth() : Float.MAX_VALUE;
}
public void setFractionTranslationX(float translationX) {
int width = getWidth();
super.setTranslationX(width > 0 ? width * translationX : Float.MAX_VALUE);
}
public float getFractionTranslationY() {
return getHeight() > 0 ? super.getTranslationX() / getHeight() : Float.MAX_VALUE;
}
public void setFractionTranslationY(float translationY) {
int height = getHeight();
super.setTranslationY(height > 0 ? height * translationY : Float.MAX_VALUE);
}
public float getAnimWidth() {
return getLayoutParams().width;
}
public void setAnimWidth(int animWidth) {
getLayoutParams().width = animWidth;
requestLayout();
}
}
layout file of fragment:
fragment_main_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<com.bbi.views.FractionLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/esc_app_background"
android:orientation="vertical">
...........
...........
</com.bbi.views.FractionLinearLayout>
Custom animation xml file:
alide_in_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator">
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#integer/animation_time"
android:propertyName="fractionTranslationX"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
</set>
slide_out_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_interpolator">
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="#integer/animation_time"
android:propertyName="fractionTranslationX"
android:valueFrom="0"
android:valueTo="-1"
android:valueType="floatType" />
</set>
Code to add fragment on Activity:
getFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_in_left;, R.anim.slide_out_left)
.replace(R.id.frameTopContainer, newsToolFragment)
.commitAllowingStateLoss();
When i replace com.views.FractionLinearLayout to LinearLayout in fragment_main_layout.xml, everything works fine(not animation obvious as i have disabled animation and removed property custom animation).
Finally solved my issue by reading animation_scale flag and removing setCustomAnimations() method according to that.
The problem is when you disabled the animation, the animator will call setFractionTranslationX() to pass the initial value and final value at the same time, and it would be a very early moment that your view not yet have width and height, so you will translated your view to Float.MAX_VALUE every time.
To correctly set your view x and y position whenever animation enable or not, you can :
private float mXFraction;
private float mYFraction;
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setFractionTranslationX(mXFraction);
setFractionTranslationY(mYFraction);
}
public float getFractionTranslationX() {
return mXFraction;
}
public void setFractionTranslationX(float xFraction) {
mXFraction = xFraction;
int width = getWidth();
if (width > 0) setTranslationX(xFraction * width);
}
public float getFractionTranslationY() {
return mYFraction;
}
public void setFractionTranslationY(float yFraction) {
mYFraction = yFraction;
int height = getHeight();
if (height > 0) setTranslationY(yFraction * height);
}
Related
I'm trying to add custom transition to fragments. As the Link suggested , the proper solution is to create a custom view as fragment container and then by animating the new added property , make fragment's transition run. but absolutely its on java. I implemented that as below in C# and Xamarin:
class SmartFrameLayout : FrameLayout
{
public SmartFrameLayout(Context context) : base(context) { }
public SmartFrameLayout(Context context, IAttributeSet attrs) : base(context, attrs) { }
public SmartFrameLayout(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr) { }
public SmartFrameLayout(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes) { }
//public float getXFraction()
//{
// if (Width == 0) return 0;
// return GetX() / Width;
//}
//public void setXFraction(float fraction)
//{
// Log.Debug("Fraction", fraction.ToString());
// float xx = GetX();
// SetX(xx * fraction);
//}
//private float XFraction;
public float XFraction
{
get {
if (Width == 0) return 0;
return GetX() / Width;
}
set {
float xx = GetX();
SetX(xx * value);
}
}
}
As you can see, first I tried to implement that same as the tutorial (Except that c# doesn't support read-only local variable as a "final" replacement!)
but in objectAnimator the property did not called properly. Then I think maybe using C# property will solve the problem. But it didn't.
Here is my animation xml file, named "from_right.xml":
<?xml version="1.0" encoding="utf-8" ?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:propertyName="xFraction"
android:valueType="floatType"
android:valueFrom="1.0"
android:valueTo="0"
android:duration="500"/>
I changed propertyName to "XFraction" or even anything else, but the results was the same.
Using "x" as propertyName and "1000" as valueFrom works well.
So I figured out the main problem is that the objectAnimator could not call setXFraction at all!
Please tell me what I'm doing wrong, or if there is a better solution to get exactly the screen width for valueFrom in objectAnimator !
You need to expose the setXFraction and getXFraction methods to Java; they are currently only within managed code and are not accesible to the Java VM.
Use the [Export] attribute to expose these methods to Java so that the animator can use them:
[Export]
public float getXFraction()
{
if (Width == 0) return 0;
return GetX() / Width;
}
[Export]
public void setXFraction(float fraction)
{
Log.Debug("Fraction", fraction.ToString());
float xx = GetX();
SetX(xx * fraction);
}
This will result in the following Java code being generated in SmartFrameLayouts Android Callable Wrapper:
public float getXFraction ()
{
return n_getXFraction ();
}
private native float n_getXFraction ();
public void setXFraction (float p0)
{
n_setXFraction (p0);
}
private native void n_setXFraction (float p0);
I've tried the custom view and tilt the image to 45 degree successfully but I want to tilt the whole child layoout at some angle so that whatever I'll add in that child layout will automactically tiled .. For reference please take a look at the attached picture
even I have tried this code but it wont help
public class CustomLinear extends LinearLayout{
private Matrix mForward = new Matrix();
private Matrix mReverse = new Matrix();
private float[] mTemp = new float[2];
public CustomLinear(Context context) {
super(context);
}
public CustomLinear(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.rotate(75, getWidth() / 2, getHeight() / 2);
mForward = canvas.getMatrix();
mForward.invert(mReverse);
canvas.save();
canvas.setMatrix(mForward); // This is the matrix we need to use for
// proper positioning of touch events
super.dispatchDraw(canvas);
canvas.restore();
invalidate();
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
event.setLocation(getWidth() - event.getX(), getHeight() - event.getY());
return super.dispatchTouchEvent(event);
}
}
I thing it is possible using rotate animation. you can apply animation on the whole child layout with 0 duration in On_create.
Here is the animation code
<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="-90"
android:pivotX="50%"
android:pivotY="50%"
android:duration="0"
android:fillAfter="true">
</rotate>
You can set the rotation angle as per your need.
Then use given code in your Activity's onCreate,
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.myscreen);
Animation rotate_anim = AnimationUtils.loadAnimation(this, R.anim.rotation);
LayoutAnimationController anim_controller = new LayoutAnimationController(rotate_anim, 0);
FrameLayout layout = (FrameLayout)findViewById(R.id.MyScreen_ContentLayout);
layout.setLayoutAnimation(anim_controller);
}
Make custom (tilted/rotated) xml views and call it all in the main view.
Also, take a look at the following link this may help you.
http://mindfreakconcepts.blogspot.com/2013/03/how-to-rotate-listview-items-in-android.html
I could be wrong but from my understanding you have to use animation to get the effect that you want instead of draw. There is a similar thread, here that might be worth checking out.
I got a ListView with items in it.
When the user clicks an item it's height should scale to zero and all items below should scroll up.
My code below doesnt work.
With my code the item which was clicked scales right, but the items below dont scroll up, they stay at the same position.
I've also tried it with an LinearLayout but there is the same problem.
There is an app which does this right. It's called Tasks.
My current implementation looks like this:
#Override
public void onItemClick(AdapterView<?> arg0, View v, final int index,
long id) {
Animation anim = AnimationUtils.loadAnimation(getActivity(),
R.anim.scaleup);
v.startAnimation(anim);
}
<set android:shareInterpolator="false" >
<scale
android:duration="700"
android:fillAfter="false"
android:fillBefore="false"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:pivotY="0%"
android:toXScale="1.0"
android:toYScale="0.0" />
</set>
Here's a class I made (modified from source I found here) that may give you the functionality you want.
public class FadeUpAnimation extends Animation {
int mFromHeight;
View mView;
public FadeUpAnimation(View view) {
this.mView = view;
this.mFromHeight = view.getHeight();
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight;
newHeight = (int) (mFromHeight * (1 - interpolatedTime));
mView.getLayoutParams().height = newHeight;
mView.setAlpha(1 - interpolatedTime);
mView.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
Then this is how I'm using it
View tv = ...
Animation a = new FadeUpAnimation(tv);
a.setInterpolator(new AccelerateInterpolator());
a.setDuration(300);
tv.setAnimation(a);
tv.startAnimation(a);
You can play with it to see if you can get it to fit your needs.
Will you use the clicked item again? If not, then you could
Wait until the animation finishes
Delete the item from wherever you store the underlaying data
Then call the notifyDataSetChanged() method of your listadapter
The Android don't act like HTML, when you change the width, height or visibility in a view, the other views don't update theirs positions.
If you need to do that, you must update all the listview and your views inside, individually. This is a complex code to do.
I need to create a circle that rotates and contains data for my application. Should I create a customized object for my application or should I make a in-application widget?
While on the topic, how do you refer to a widget within an application instead of a stand alone widget for the android desktop?
This is a rotatable LinearLayout that you can put everything in it and you can rotate it by degree if you customize it. use rotate() method to rotate it and...
enjoy! ;)
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class RotateLinearLayout extends LinearLayout {
private Matrix mForward = new Matrix();
private Matrix mReverse = new Matrix();
private float[] mTemp = new float[2];
private float degree = 0;
public RotateLinearLayout(Context context) {
super(context);
}
public RotateLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void dispatchDraw(Canvas canvas) {
try {
if (degree == 0) {
super.dispatchDraw(canvas);
return;
}
canvas.rotate(degree, getWidth() / 2, getHeight() / 2);
mForward = canvas.getMatrix();
mForward.invert(mReverse);
canvas.save();
canvas.setMatrix(mForward); // This is the matrix we need to use for
// proper positioning of touch events
super.dispatchDraw(canvas);
canvas.restore();
invalidate();
} catch (Exception e) {
}
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (degree == 0) {
return super.dispatchTouchEvent(event);
}
// final float[] temp = mTemp;
// temp[0] = event.getX();
// temp[1] = event.getY();
// mReverse.mapPoints(temp);
// event.setLocation(temp[0], temp[1]);
event.setLocation(getWidth() - event.getX(), getHeight() - event.getY());
return super.dispatchTouchEvent(event);
}
public void rotate() {
if (degree == 0) {
degree = 180;
} else {
degree = 0;
}
}
}
Update:
add this code to your xml layout and put your Views like ImageView or another LinearLayout in it :
<org.mabna.order.ui.RotateLinearLayout android:id="#+id/llParent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal" >
<ImageView
android:id="#+id/myImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:src="#drawable/main01" />
</org.mabna.order.ui.RotateLinearLayout>
in onCreate() method:
llParent = (RotateLinearLayout) this.findViewById(R.id.llParent);
in onClickListener of a button:
protected void btnRotate_onClick() {
llParent.rotate();
}
Update2:
You can use an animation for rotation before real rotation (llParent.rotate();). it needs an animation layout like rotate_dialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000" android:fromDegrees="-180" android:toDegrees="0"
android:pivotX="50%" android:pivotY="50%" android:fillAfter="true" />
and in your code:
protected void btnRotate_onClick() {
// rotate
Animation rotateAnimation = AnimationUtils.loadAnimation(this,
R.anim.rotate_dialog);
llParent.startAnimation(rotateAnimation);
llParent.rotate();
}
There is a fairly easy way to make a rotating animation from a custom widget derived from the View class. After the view is created and placed in your layout, you can call View.setAnimation(Animation) or View.startAnimation(Animation), supplying a RotateAnimation on the view to start it. Here is an example of a rotation animation defined in xml, that can be loaded from your activity with getResources().getAnimation(int).
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
I want to create a rotating progress image, and wonder what's the best way to proceed. I can make it work with an animation list with for example 12 images changing every 100ms. This works fine, but it's quite tedious to create 12 images or for every size and resolution:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="#drawable/ic_loading_grey_on_black_01" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_02" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_03" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_04" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_05" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_06" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_07" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_08" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_09" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_10" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_11" android:duration="100" />
<item android:drawable="#drawable/ic_loading_grey_on_black_12" android:duration="100" />
I suppose that an easier solution is to use one image per resolution, but rather rotate it for each frame. In the platform resources (android-sdk-windows/platforms...) I found something called animated-rotate in the file drawable/search_spinner.xml, but if I copy the code get a compiler error complaining about android:framesCount and android:frameDuration (Google APIs 2.2 in Eclipse):
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="#drawable/spinner_black_20"
android:pivotX="50%"
android:pivotY="50%"
android:framesCount="12"
android:frameDuration="100" />
I have also tried using a repeating rotate animation (using in the anim resource folder), but I actually prefer the look of the animation list version.
What is the recommended way of solving this problem?
Rotate drawable suggested by Praveen won't give you control of frame count. Let's assume you want to implement a custom loader which consists from 8 sections:
Using animation-list approach, you need to create 8 frames rotated by 45*frameNumber degrees manually. Alternatively, you can use 1st frame and set rotation animation to it:
File res/anim/progress_anim.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite" />
File MainActivity.java
Animation a = AnimationUtils.loadAnimation(getContext(), R.anim.progress_anim);
a.setDuration(1000);
imageView.startAnimation(a);
This will give you smooth animation instead of 8-stepped. To fix this we need to implement custom interpolator:
a.setInterpolator(new Interpolator() {
private final int frameCount = 8;
#Override
public float getInterpolation(float input) {
return (float)Math.floor(input*frameCount)/frameCount;
}
});
Also you can create a custom widget:
File res/values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ProgressView">
<attr name="frameCount" format="integer"/>
<attr name="duration" format="integer" />
</declare-styleable>
</resources>
File ProgressView.java:
public class ProgressView extends ImageView {
public ProgressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setAnimation(attrs);
}
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
setAnimation(attrs);
}
public ProgressView(Context context) {
super(context);
}
private void setAnimation(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ProgressView);
int frameCount = a.getInt(R.styleable.ProgressView_frameCount, 12);
int duration = a.getInt(R.styleable.ProgressView_duration, 1000);
a.recycle();
setAnimation(frameCount, duration);
}
public void setAnimation(final int frameCount, final int duration) {
Animation a = AnimationUtils.loadAnimation(getContext(), R.anim.progress_anim);
a.setDuration(duration);
a.setInterpolator(new Interpolator() {
#Override
public float getInterpolation(float input) {
return (float)Math.floor(input*frameCount)/frameCount;
}
});
startAnimation(a);
}
}
File activity_main.xml:
<com.example.widget.ProgressView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_progress"
app:frameCount="8"
app:duration="1000"/>
File res/anim/progress_anim.xml: listed above
You have to create a drawable xml file like below:
Code:
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:pivotX="50%" android:pivotY="50%" android:fromDegrees="0"
android:toDegrees="360" android:drawable="#drawable/imagefile_to_rotate" />
I found vokilam's answer to be the best one to create a nice stepped/staggered animation. I went for his final suggestion and made a custom widget, the only problem I encountered was that setting visibility wouldn't work because it was animated and thus would always be visible...
I adjusted his code (ProgressView.java which I renamed StaggeredProgress.java) like this:
public class StaggeredProgress extends ImageView {
private Animation staggered;
public StaggeredProgress(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setAnimation(attrs);
}
public StaggeredProgress(Context context, AttributeSet attrs) {
super(context, attrs);
setAnimation(attrs);
}
public StaggeredProgress(Context context) {
super(context);
}
private void setAnimation(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.StaggeredProgress);
int frameCount = a.getInt(R.styleable.StaggeredProgress_frameCount, 12);
int duration = a.getInt(R.styleable.StaggeredProgress_duration, 1000);
a.recycle();
setAnimation(frameCount, duration);
}
public void setAnimation(final int frameCount, final int duration) {
Animation a = AnimationUtils.loadAnimation(getContext(), R.anim.progress_anim);
a.setDuration(duration);
a.setInterpolator(new Interpolator() {
#Override
public float getInterpolation(float input) {
return (float)Math.floor(input*frameCount)/frameCount;
}
});
staggered = a;
//startAnimation(a);
}
#Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if( visibility == View.VISIBLE )
startAnimation(staggered);
else
clearAnimation();
}
}
This way setting the view's visibility starts and stops the animation as required...Many thanks again to vokilam!
see examples here
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/index.html
specifically:
Progress Bar
Incremental
Demonstrates large and small rotating progress indicators that can be incremented or decremented in units.
Smooth
Demonstrates large and small continuously rotating progress indicators used to indicate a generic "busy" message.
Dialogs
Demonstrates a ProgressDialog, a popup dialog that hosts a progress bar. This example demonstrates both determinate and indeterminate progress indicators.
In Title Bar
Demonstrates an Activity screen with a progress indicator loaded by setting the WindowPolicy's progress indicator feature.
SACPK's solution definitely works. Another solution can be to use <animated-rotate> just like in question and remove android:framesCount="12"
android:frameDuration="100" attributes for those the compiler complains. It still works even for my 8-frame image.
However, I havn't figured out how to control the speed of the animation :(.
Thank #vokilam. This similar solution (a custom view that rotates automatically) uses <animation-list> dynamically in its implementation:
public class FramesAnimatorView extends AppCompatImageView {
private int framesCount;
private int duration;
private Bitmap frameBitmap;
public FramesAnimatorView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
public FramesAnimatorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public FramesAnimatorView(Context context) { super(context); }
private void init(Context context, AttributeSet attrs) {
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FramesAnimatorView);
framesCount = typedArray.getInt(R.styleable.FramesAnimatorView_framesCount, 12);
duration = typedArray.getInt(R.styleable.FramesAnimatorView_duration, 1200);
typedArray.recycle();
// Method 1: Use <rotate> as Animation (RotateAnimation) and startAnimation() (Rotate view itself).
//method1(framesCount, duration);
// Method 2: Use <rotate> as Drawable (RotateDrawable) and ObjectAnimator. Usable for API 21+ (because of using RotateDrawable.setDrawable).
//method2();
// Method 3 (Recommended): Use <animation-list> (AnimationDrawable) dynamically.
final int frameDuration = this.duration / framesCount;
final AnimationDrawable animationDrawable = (AnimationDrawable) getDrawable();
for (int i = 0; i < framesCount; i++)
animationDrawable.addFrame(
new RotatedDrawable(frameBitmap, i * 360f / framesCount, getResources()),
frameDuration);
animationDrawable.start();
}
#Override public void setImageResource(int resId) { //info();
frameBitmap = BitmapFactory.decodeResource(getResources(), resId);
super.setImageDrawable(new AnimationDrawable());
}
#Override public void setImageDrawable(#Nullable Drawable drawable) { //info();
frameBitmap = drawableToBitmap(drawable);
super.setImageDrawable(new AnimationDrawable());
}
#Override public void setImageBitmap(Bitmap bitmap) { //info();
frameBitmap = bitmap;
super.setImageDrawable(new AnimationDrawable());
}
/**
* See #android-developer's answer on stackoverflow.com.
*/
private static class RotatedDrawable extends BitmapDrawable {
private final float degrees;
private int pivotX;
private int pivotY;
RotatedDrawable(Bitmap bitmap, float degrees, Resources res) {
super(res, bitmap);
pivotX = bitmap.getWidth() / 2;
pivotY = bitmap.getHeight() / 2;
this.degrees = degrees;
}
#Override public void draw(final Canvas canvas) {
canvas.save();
canvas.rotate(degrees, pivotX, pivotY);
super.draw(canvas);
canvas.restore();
}
}
/**
* See #André's answer on stackoverflow.com.
*/
#NonNull private static Bitmap drawableToBitmap(Drawable drawable) {
final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
See Android-FramesAnimatorView on GitHub for full (and probably more updated) source code.