ホームページ > 記事 > ウェブフロントエンド > Android アニメーション 3 部作の 1 つ アニメーションとレイアウトを表示Animation_html/css_WEB-ITnose
この記事では、AndroidのTweenアニメーションとフレームアニメーション、そしてレイアウトアニメーションについてまとめました。
トゥイーンアニメーションはトゥイーンアニメーションとも呼ばれます。アニメーション効果は、ビューの位置、サイズ、透明度、角度を変更することで実現されます。
、
TranslateAnimation、ScaleAnimation、AlphaAnimation を使用します。 トゥイーン アニメーションは XML (res/anim/xxx) を通じて定義でき、その後
AnimationUtils クラスを通じてロードでき、完全なコードを通じて設定することもできます。 XML構文の紹介 <?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@[package:]anim/interpolator_resource" android:shareInterpolator=["true" | "false"] > <alpha android:fromAlpha="float" android:toAlpha="float" /> <scale android:fromXScale="float" android:toXScale="float" android:fromYScale="float" android:toYScale="float" android:pivotX="float" android:pivotY="float" /> <translate android:fromXDelta="float" android:toXDelta="float" android:fromYDelta="float" android:toYDelta="float" /> <rotate android:fromDegrees="float" android:toDegrees="float" android:pivotX="float" android:pivotY="float" /> <set> ... </set></set>
public static final int INFINITE = -1;public static final int RESTART = 1;public static final int REVERSE = 2;
主にそのサブクラスとAnimationListenerを使用します:
public static interface AnimationListener { /** * 动画开始的时候回调 * * @param animation The started animation. */ void onAnimationStart(Animation animation); /** * 动画结束的时候回调。但是当设置动画重复次数为INFINITE的时候,该方法不会回调。 * * @param animation The animation which reached its end. */ void onAnimationEnd(Animation animation); /** * 动画重复播放的时候回调 * * @param animation The animation which was repeated. */ void onAnimationRepeat(Animation animation); }
アニメーション操作をさらに実行するには、このリスナーを追加します。
Interpolator - インターポレーター
アニメーションを紹介する前に、まず「インターポレーター」について話さなければなりません。インターポレータの意味は、アニメーションを再生するときに再生レートを変更することです。これにより、アニメーションを速くしたり遅くしたりすることができます。
Baseinterpolator サブクラス リソース ID 説明
変更を加速します (ゆっくり始めて、どんどん速くなります) | 減速インターポレーター + | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@android:anim/linear_interpolator | 線形均一変化 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@android:anim/overshoot_interpolator | 最後に臨界値を超え、ゆっくりと終了値に戻る | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@ android:anim/anticipate_interpolator | 最初に少し反対方向に変更してから、再生を加速します | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@android:anim/anitcipate_overshoot_interpolator | 最初に少し変更します反対方向に、その後、再生を加速して終了値を超えます。ある時点で、ゆっくりと終了値に戻ります。着陸 | @@Android: NIM/Cycle_interpolator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
自定义Interpolator一般来说,官方API给的这几个插值器就够实用了。不过还可以自定义Interpolator。可以简单的对系统的插值器进行一些参数值的修改: <?xml version="1.0" encoding="utf-8"?><InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android" android:attribute_name="value" /> 这里推荐大家一个第三方的Interpolator库: https://github.com/cimi-chen/EaseInterpolator 公共XML属性及对应的方法
android:zAdjustment:允许在动画播放期间,调整播放内容在Z轴方向的顺序: ScaleAnimation – 缩放动画
<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="http://schemas.android.com/apk/res/android" android:background="@color/blue_light" android:duration="1000" android:fillAfter="false" android:fillBefore="true" android:fromXScale="1" android:fromYScale="1" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:pivotX="50%" android:pivotY="50%" android:repeatCount="1" android:repeatMode="restart" android:startOffset="500" android:toXScale="0" android:toYScale="0" android:zAdjustment="bottom" /> 然后通过AnimationUtils类装载动画,进行应用。 Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale_anim);targetIv.startAnimation(scaleAnimation);代码定义缩放动画 ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.5f, 1.0f, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);scaleAnimation.setDuration(1000);scaleAnimation.setInterpolator(new OvershootInterpolator());scaleAnimation.setFillAfter(true);targetIv.startAnimation(scaleAnimation); ScaleAnimation有4个构造方法。 public ScaleAnimation(Context context, AttributeSet attrs) {} public ScaleAnimation(float fromX, float toX, float fromY, float toY) {} public ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) {} public ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {} 第一个构造用于从资源文件中加载资源。我们主要用后三个。后面三个构造的区别就在设置变换中轴点与否。不指定pivotXType和pivotYType的话,默认采用ABSOLUTE形式,pivotX与pivotY的值都是相对于(0,0)左上角偏移的。 pivotXType可设置的参数有三种:ABSOLUTE、RELATE_TO_SELF、RELATE_TO_PARENT。 效果如下: RotateAnimation – 旋转动画
<?xml version="1.0" encoding="utf-8"?><rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2500" android:fillAfter="true" android:fromDegrees="-20" android:interpolator="@android:anim/overshoot_interpolator" android:pivotX="50%" android:pivotY="50%" android:toDegrees="320" />代码中设置旋转动画 RotateAnimation rotateAnimation = new RotateAnimation(0.0f, 550.0f, Animation.RELATIVE_TO_SELF, 0.3f, Animation.RELATIVE_TO_SELF, 0.3f);rotateAnimation.setDuration(1500);rotateAnimation.setInterpolator(new OvershootInterpolator());rotateAnimation.setFillAfter(true);targetIv.startAnimation(rotateAnimation); 效果图如下: TranslateAnimation – 平移动画
<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromXDelta="0" android:fromYDelta="0" android:interpolator="@android:anim/anticipate_overshoot_interpolator" android:toXDelta="50%p" android:toYDelta="50%p" />代码中设置平移动画 TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 0);translateAnimation.setDuration(1000);translateAnimation.setInterpolator(new AnticipateOvershootInterpolator());targetIv.startAnimation(translateAnimation); AlphaAnimation – 渐变动画
<?xml version="1.0" encoding="utf-8"?><alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromAlpha="1.0" android:interpolator="@android:anim/linear_interpolator" android:repeatCount="1" android:repeatMode="reverse" android:toAlpha="0.0" />代码中设置渐变动画: AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.2f);alphaAnimation.setDuration(1500);alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());alphaAnimation.setRepeatMode(Animation.REVERSE);alphaAnimation.setRepeatCount(1);targetIv.startAnimation(alphaAnimation); AnimationSet – 动画集合上面都是一个个的单独的动画,我们可以将很多个单独的动画组合到一起成为一个集合。 动画集合也可以在xml中设置。需要用标签包括其他简单的动画。比上述公共动画属性多了一个android:shareInterpolator=”boolean”,表示是否对子动画设置相同的插值器。 xml中设置set动画集合<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" android:shareInterpolator="false"> <alpha android:duration="1500" android:fillAfter="true" android:fromAlpha="1.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="0.2" /> <scale android:duration="1000" android:fromXScale="0.8" android:fromYScale="0.8" android:interpolator="@android:anim/linear_interpolator" android:pivotX="60%" android:pivotY="20%" android:startOffset="1500" android:toXScale="0.3" android:toYScale="0.5" /> <translate android:duration="1000" android:fromXDelta="0" android:fromYDelta="0" android:interpolator="@android:anim/bounce_interpolator" android:startOffset="2500" android:toXDelta="200" android:toYDelta="200" /> <rotate android:duration="1000" android:fromDegrees="50" android:interpolator="@android:anim/anticipate_overshoot_interpolator" android:pivotX="50%p" android:pivotY="50%p" android:startOffset="3500" android:toDegrees="360" /></set> 再次修改之后,代码如下: <?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" android:shareInterpolator="false"> <alpha android:duration="1500" android:fillAfter="true" android:fromAlpha="1.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="0.2" /> <scale android:duration="1000" android:fillBefore="false" android:fillEnabled="true" android:fromXScale="0.8" android:fromYScale="0.8" android:interpolator="@android:anim/linear_interpolator" android:pivotX="60%" android:pivotY="20%" android:startOffset="1500" android:toXScale="0.3" android:toYScale="0.5" /> <translate android:duration="1000" android:fromXDelta="0" android:fromYDelta="0" android:interpolator="@android:anim/bounce_interpolator" android:startOffset="2500" android:toXDelta="200" android:toYDelta="200" /> <rotate android:duration="1000" android:fillBefore="false" android:fillEnabled="true" android:fromDegrees="50" android:interpolator="@android:anim/anticipate_overshoot_interpolator" android:pivotX="50%p" android:pivotY="50%p" android:startOffset="3500" android:toDegrees="360" /></set> 效果如下: Frame动画Frame动画就是把图片一帧一帧的播放出来的显示效果,类似于gif图片。帧动画设置很简单,只需要把每一帧对应的图片按照顺序添加进去,然后设置每一帧的显示时长,然后为view控件设置该动画,播放就行了。 xml设置帧动画:<?xml version="1.0" encoding="utf-8"?><animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/person1" android:duration="100" /> <item android:drawable="@drawable/person2" android:duration="100" /> <item android:drawable="@drawable/person3" android:duration="100" /> <ite android:drawable="@drawable/person4" android:duration="100" /> <item android:drawable="@drawable/person5" android:duration="100" /> <item android:drawable="@drawable/person6" android:duration="100" /> <item android:drawable="@drawable/person7" android:duration="100" /></animation-list> 给ImageView设置动画: targetIv.setBackgroundResource(R.drawable.frame_anim);AnimationDrawable animationDrawable = (AnimationDrawable) targetIv.getBackground();animationDrawable.start();代码中设置帧动画 AnimationDrawable animationDrawable = new AnimationDrawable();animationDrawable.setOneShot(false);animationDrawable.addFrame(getResources().getDrawable(R.drawable.person1), 200);animationDrawable.addFrame(getResources().getDrawable(R.drawable.person2), 200);animationDrawable.addFrame(getResources().getDrawable(R.drawable.person3), 200);animationDrawable.addFrame(getResources().getDrawable(R.drawable.person4), 200);animationDrawable.addFrame(getResources().getDrawable(R.drawable.person5), 200);targetIv.setImageDrawable(animationDrawable);animationDrawable.start(); LayoutAnimationControllerTween Animation和Frame Animation都是针对单个view操作的。而LayoutAnimationController可以针对一个ViewGroup进行动画操作,可以让一组view的每个view按照一定的规则展示动画。 一般对ListView使用layoutAnimation动画,对GridView使用gridLayoutAnimation动画。对RecyclerView来说,正常情况下只能使用layoutAnimation动画,应用gridLayoutAnimation动画的时候会报错。不错可以针对RecyclerView生成一个子类做一下处理进行支持gridLayoutAnimation动画。
<?xml version="1.0" encoding="utf-8"?><layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:animation="@anim/item_list_anim" android:animationOrder="normal" android:delay="0.2" android:interpolator="@android:anim/bounce_interpolator" /> <?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:shareInterpolator="true"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" /> <translate android:fromXDelta="-100%" android:toXDelta="0%" /></set>代码中定义LayoutAnimation public LayoutAnimationController(Animation animation) { this(animation, 0.5f);} public LayoutAnimationController(Animation animation, float delay) { mDelay = delay; setAnimation(animation);} LayoutAnimationController有三个构造函数,常用的时候上面两个。delay表示每个子view启动动画的延迟时间,默认是0.5f。delay以秒为单位 。 Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_list_anim); LayoutAnimationController layoutAnimationController = new LayoutAnimationController(animation); layoutAnimationController.setInterpolator(new AccelerateInterpolator()); layoutAnimationController.setDelay(0.5f); layoutAnimationController.setOrder(LayoutAnimationController.ORDER_RANDOM); recyclerView.setLayoutAnimation(layoutAnimationController); GridLayoutAnimationControllerGridLayoutAnimationController是LayoutAnimationController的子类。针对GridView做动画操作。
<GridView android:id="@+id/test_grid_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:columnWidth="60dp" android:gravity="center" android:horizontalSpacing="10dp" android:layoutAnimation="@anim/grid_layout_anim" android:numColumns="3" android:padding="10dp" android:scrollbars="none" android:stretchMode="columnWidth" android:verticalSpacing="10dp" /> <?xml version="1.0" encoding="utf-8"?><gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:animation="@anim/item_anim_alpha" android:columnDelay="0.5" android:direction="bottom_to_top|right_to_left" android:directionPriority="row" /> <?xml version="1.0" encoding="utf-8"?><alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromAlpha="0.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="1.0" />代码中设置 同样是使用一个Animation构造出GridLayoutAnimation对象,然后设置各种参数,最后设置此动画GridView即可。 Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_anim_alpha);GridLayoutAnimationController gridLayoutAnimationController = new GridLayoutAnimationController(animation);gridLayoutAnimationController.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP | GridLayoutAnimationController.DIRECTION_RIGHT_TO_LEFT);gridLayoutAnimationController.setDirectionPriority(GridLayoutAnimationController.PRIORITY_ROW);gridRecyclerView.setLayoutAnimation(gridLayoutAnimationController); 效果如下: RecyclerView扩展正常情况下,我们可以对RecyclerView使用LayoutAnimation动画。但是如果对RecycleView使用动画的时候出现以下错误: AndroidRuntime: FATAL EXCEPTION: main Process: com.jacksen.demo.view, PID: 30770 java.lang.ClassCastException: android.view.animation.LayoutAnimationController$AnimationParameters cannot be cast to android.view.animation.GridLayoutAnimationController$AnimationParameters at android.view.animation.GridLayoutAnimationController.getDelayForView(GridLayoutAnimationController.java:299) at android.view.animation.LayoutAnimationController.getAnimationForView(LayoutAnimationController.java:321) at android.view.ViewGroup.bindLayoutAnimation(ViewGroup.java:3717) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2892) ...... 意思就是GridLayoutAnimationController.AnimationParameters不能强转成LayoutAnimationController.AnimationParameters。 RecyclerView的出现本来就是替代Listview的,但是它有可以展示出GridView的效果,但是怎么让RecyclerView设置GridLayoutManager的时候应用gridLayoutAnimation动画呢? 我们先来看看Gridview怎么实现的? 在GridView源码里面搜索”LayoutAnimation”关键字发现,只有一个attachLayoutAnimationParameters()的函数,里面将layoutAnimationParameters强转成GridLayoutAnimationController.AnimationParameters。 @Override protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) { GridLayoutAnimationController.AnimationParameters animationParams = (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters; if (animationParams == null) { animationParams = new GridLayoutAnimationController.AnimationParameters(); params.layoutAnimationParameters = animationParams; } animationParams.count = count; animationParams.index = index; animationParams.columnsCount = mNumColumns; animationParams.rowsCount = count / mNumColumns; if (!mStackFromBottom) { animationParams.column = index % mNumColumns; animationParams.row = index / mNumColumns; } else { final int invertedIndex = count - 1 - index; animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns); animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns; } } 然后就想到去RecyclerView中去找attachLayoutAnimationParameters()方法,但是没有,其父类ViewGroup里面有此方法: protected void attachLayoutAnimationParameters(View child, LayoutParams params, int index, int count) { LayoutAnimationController.AnimationParameters animationParams = params.layoutAnimationParameters; if (animationParams == null) { animationParams = new LayoutAnimationController.AnimationParameters(); params.layoutAnimationParameters = animationParams; } animationParams.count = count; animationParams.index = index; } 由此可见RecyclerView默认实现了ViewGroup的LayoutAnimation。我们在RecyclerView中将此方法重写一下。不过要将mStackFromButtom参数的判断去掉。 public class GridRecyclerView extends RecyclerView { public GridRecyclerView(Context context) { super(context); } public GridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setAdapter(Adapter adapter) { super.setAdapter(adapter); } @Override public void setLayoutManager(LayoutManager layout) { if (layout instanceof GridLayoutManager) { super.setLayoutManager(layout); } else { throw new ClassCastException("you should only use the GridLayoutManager as LayoutManager when you use this " + this.getClass().getSimpleName() + " class"); } } @Override protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) { if (getLayoutManager() != null && getLayoutManager() instanceof GridLayoutManager) { GridLayoutAnimationController.AnimationParameters animationParams = (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters; if (animationParams == null) { animationParams = new GridLayoutAnimationController.AnimationParameters(); params.layoutAnimationParameters = animationParams; } int mNumColumns = ((GridLayoutManager) getLayoutManager()).getSpanCount(); animationParams.count = count; animationParams.index = index; animationParams.columnsCount = mNumColumns; animationParams.rowsCount = count / mNumColumns; final int invertedIndex = count - 1 - index; animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns); animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns; } else { super.attachLayoutAnimationParameters(child, params, index, count); } }} 当我们使用GridLayoutManager的时候,不能使用此属性。 /** * stackFromEnd is not supported by GridLayoutManager. Consider using * {@link #setReverseLayout(boolean)}. */ @Override public void setStackFromEnd(boolean stackFromEnd) { if (stackFromEnd) { throw new UnsupportedOperationException( "GridLayoutManager does not support stack from end." + " Consider using reverse layout"); } super.setStackFromEnd(false); } 此篇blog到此结束~ 参考: http://developer.android.com/intl/zh-cn/guide/topics/graphics/view-animation.html |