View 动画框架
使用 View 动画框架可以在 View 上执行补间动画。 补间动画是指,只要指定动画的开始与结束的“关键帧”,而动画变化的“中间帧”由系统计算并补齐。 动画并没有改变 View 的实际位置,仅是改变了 View 的显示位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 FILE LOCATION: res/anim/filename.xml The filename will be used as the resource ID. COMPILED RESOURCE DATATYPE: Resource pointer to an Animation. RESOURCE REFERENCE: In Java: R.anim.filename In XML: @[package:]anim/filename 文件位置: res /anim/ filename.xml 文件名将用作资源ID。 编制资源数据类型: 指向动画的资源指针。 资源引用: 在Java: R.anim.filename 在XML: @包:anim/文件名 // XML使用 // res /anim/ anim_layout.xml <?xml version="1.0" encoding="utf-8" ?> <layoutAnimation xmlns:android ="http://schemas.android.com/apk/res/android" android:animation ="@anim/anim_file" android:animationOrder ="normal" android:delay ="0.5" > </layoutAnimation > // res /layout/ activity_main.xml <ListView android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layoutAnimation ="@anim/anim_layout" android:divider ="#f1f1f1" android:dividerHeight ="1dp" > </ListView >
语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <?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" // 透明度初始值。其中,0.0 是完全透明,1.0 是完全不透明。 android:toAlpha ="float" // 透明度结束值。其中,0.0 是完全透明,1.0 是完全不透明。 /> <--缩放动画--> <scale android:fromXScale ="float" // 水平方向缩放比例的初始值,其中1.0 是没有任何变化。 android:toXScale ="float" // 水平方向缩放比例的结束值,其中1.0 是没有任何变化。 android:fromYScale ="float" // 竖直方向缩放比例的初始值,其中1.0 是没有任何变化。 android:toYScale ="float" // 竖直方向缩放比例的结束值,其中1.0 是没有任何变化。 android:pivotX ="float" // 缩放中心点的x 坐标 android:pivotY ="float" // 缩放中心点的y 坐标 /> <--平移动画--> <translate android:fromXDelta ="float or percentage" // 移动起始点的x 坐标,表现形式有三种; // 1. 相对于自己的左边界的距离,单位像素值。(例如 "5 ") // 2. 相对于自己的左边界的距离与自身宽度的百分比。(例如 "5 %") // 3. 相对于父View 的左边界的距离与父View 宽度的百分比。(例如 "5 %p ") android:toXDelta ="float or percentage" // 移动结束点的x 坐标,表现形式同上; android:fromYDelta ="float or percentage" // 移动起始点的y 坐标,表现形式有三种; // 1. 相对于自己的上边界的距离,单位像素值。(例如 "5 ") // 2. 相对于自己的上边界的距离与自身高度的百分比。(例如 "5 %") // 3. 相对于父View 的上边界的距离与父View 高度的百分比。(例如 "5 %p ") android:toYDelta ="float or percentage" // 移动结束点的y 坐标,表现形式同上; /> <--旋转动画--> <rotate android:fromDegrees ="float" // 旋转初始的角度 android:toDegrees ="float" // 旋转结束的角度 android:pivotX ="float or percentage" // 旋转中心点x 坐标,表示形式有三种: // 1. 相对于自己的左边界的距离,单位像素值。(例如 "5 ") // 2. 相对于自己的左边界的距离与自身宽度的百分比。(例如 "5 %") // 3. 相对于父View 的左边界的距离与父View 宽度的百分比。(例如 "5 %p ") android:pivotY ="float or percentage" // 旋转中心点y 坐标,表示形式有三种: // 1. 相对于自己的上边界的距离,单位像素值。(例如 "5 ") // 2. 相对于自己的上边界的距离与自身宽度的百分比。(例如 "5 %") // 3. 相对于父View 的上边界的距离与父View 高度的百分比。(例如 "5 %p ") /> <set > ... </set > </set >
四种动画示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class MainActivity extends AppCompatActivity implements View .OnClickListener { private Animation animation; private TextView tvAlpha,tvScale,tvTranslate,tvRotate; private ImageView iv; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); } private void initData () { } private void initView () { iv=findViewById(R.id.iv_main_anim); tvAlpha=findViewById(R.id.tv_main_alpha); tvScale=findViewById(R.id.tv_main_scale); tvTranslate=findViewById(R.id.tv_main_translate); tvRotate=findViewById(R.id.tv_main_rotate); tvAlpha.setOnClickListener(this ); tvScale.setOnClickListener(this ); tvTranslate.setOnClickListener(this ); tvRotate.setOnClickListener(this ); } @Override public void onClick (View view) { switch (view.getId()){ case R.id.tv_main_alpha: animation = AnimationUtils.loadAnimation(this ,R.anim.anim_alpha); iv.startAnimation(animation); break ; case R.id.tv_main_scale: animation = AnimationUtils.loadAnimation(this ,R.anim.anim_scale); iv.startAnimation(animation); break ; case R.id.tv_main_translate: animation = AnimationUtils.loadAnimation(this ,R.anim.anim_translate); iv.startAnimation(animation); break ; case R.id.tv_main_rotate: animation = AnimationUtils.loadAnimation(this ,R.anim.anim_ratate); iv.startAnimation(animation); break ; default : break ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 /** * 透明度动画 **/ <?xml version="1.0" encoding="utf-8" ?> <set xmlns:android ="http://schemas.android.com/apk/res/android" > <alpha android:fromAlpha ="1.0" android:toAlpha ="0.0" android:duration ="2000" /> </set > /** * 缩放动画 **/ <?xml version="1.0" encoding="utf-8" ?> <set xmlns:android ="http://schemas.android.com/apk/res/android" > <scale android:fromXScale ="1.0" android:fromYScale ="1.0" android:toXScale ="0.0" android:toYScale ="0.0" android:interpolator ="@android:anim/accelerate_interpolator" android:pivotX ="50%" android:pivotY ="50%" android:duration ="2000" /> </set > /** * 平移动画 **/ <?xml version="1.0" encoding="utf-8" ?> <set xmlns:android ="http://schemas.android.com/apk/res/android" > <translate android:fromXDelta ="20" android:fromYDelta ="20" android:toXDelta ="100" android:toYDelta ="100" android:duration ="2000" /> </set > /** * 旋转动画 **/ <?xml version="1.0" encoding="utf-8" ?> <set xmlns:android ="http://schemas.android.com/apk/res/android" > <rotate android:interpolator ="@android:anim/accelerate_decelerate_interpolator" android:fromDegrees ="0" android:toDegrees ="-360" android:pivotY ="50%" android:pivotX ="50%" android:duration ="2000" /> </set >
特殊场景示例 LayoutAnimation 通过布局动画(LayoutAnimation)给 ViewGroup 的子 View 指定入场动画。
也是一个 View 动画,作用于 ViewGroup,这样它的子元素出场时都会具有这种动画效果。
使用步骤 :
先写一个 tween 动画 xml
在写一个专门的 layoutAnimation xml 文件
最后给根节点的 viewGroup 设置上这个定义的 layoutAnimation
除了在 XML 中指定 LayoutAnimation 外,还可通过 LayoutAnimationController 来实现。
ListView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 /** * res/anim/zoom_in.xml **/ <?xml version="1.0" encoding="utf-8" ?> <set xmlns:android ="http://schemas.android.com/apk/res/android" android:shareInterpolator ="@android:anim/decelerate_interpolator" > <alpha android:fromAlpha ="0.0" android:toAlpha ="1.0" android:duration ="500" /> <scale android:fromXScale ="0.1" android:fromYScale ="0.1" android:toYScale ="1.0" android:toXScale ="1.0" android:pivotX ="50%" android:pivotY ="50%" android:duration ="500" /> </set >
1.通过xml的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 /** * activity_main.xml **/ <ListView android:id ="@+id/lv_main" android:padding ="10dp" android:layout_width ="match_parent" android:layout_height ="match_parent" android:layoutAnimation ="@anim/anim_layout" android:divider ="#f1f1f1" android:dividerHeight ="1dp" android:scrollbars ="none" > </ListView > /** * res/anim/anim_layout.xml **/ <?xml version="1.0" encoding="utf-8" ?> <layoutAnimation xmlns:android ="http://schemas.android.com/apk/res/android" android:animation ="@anim/zoom_in" android:animationOrder ="random" android:delay ="0.5" > </layoutAnimation >
2.通过动态代码的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class MainActivity extends AppCompatActivity implements View .OnClickListener { private TextView tvListview; private ListView lv; private String datas[]={ "Sunday" , "Monday" , "Tuesday" , "Wednesday" , "Thursday" , "Friday" , "Saturday" }; private ArrayAdapter<String> adapter; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); } private void initData () { adapter=new ArrayAdapter <>(this ,android.R.layout.simple_list_item_1,datas); lv.setAdapter(adapter); LayoutAnimationController lac = new LayoutAnimationController (AnimationUtils.loadAnimation(this ,R.anim.zoom_in)); lac.setDelay(0.5f ); lac.setOrder(LayoutAnimationController.ORDER_RANDOM); lv.setLayoutAnimation(lac); lv.setLayoutAnimationListener(new Animation .AnimationListener() { @Override public void onAnimationStart (Animation animation) { } @Override public void onAnimationEnd (Animation animation) { Toast.makeText(MainActivity.this ,"end" ,Toast.LENGTH_SHORT).show(); } @Override public void onAnimationRepeat (Animation animation) { } }); } private void initView () { tvListview=findViewById(R.id.tv_main_listview); lv=findViewById(R.id.lv_main); tvListview.setOnClickListener(this ); } @Override public void onClick (View view) { switch (view.getId()){ case R.id.tv_main_listview: lv.startLayoutAnimation(); break ; default : break ; } } }
RecyclerView
对于给RecyclerView添加初始动画的简单方法有几种:
实现一个自定义的ItemAnimator
在Adapter的onBindViewHolder()方法中添加动画
采用LayoutAnimation;使用方式与上述ListView的差不多,代码在demo中。
GridView
对于GridView,为了展示效果更好,可以使用GridLayoutAnimation来实现。 主要就是动画文件的不同,其它类似。代码在demo中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?xml version="1.0" encoding="utf-8" ?> <gridLayoutAnimation xmlns:android ="http://schemas.android.com/apk/res/android" android:animation ="@anim/item_anim_gridview" android:animationOrder ="normal" android:startOffset ="700" android:columnDelay ="15%" android:rowDelay ="15%" android:direction ="top_to_bottom|left_to_right" />
为 Activity 自定义切换动画 1.通过调用 Activity 类的 overridePendingTransition(int enterAnim, int exitAnim) 方法可以实现自定义Activity 的切换动画,注意这个方法必须在 startActivity 和 finish 调用之后被调用,否者没有效果。
Fragment(API 11 引入) 可以通过 FragmentTransaction 中的 setCustomAnimations() 来添加切换动画(View 动画)。 注意,要使用 support-v4 兼容包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class CustomSwitchingActivity extends AppCompatActivity { @Override protected void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); overridePendingTransition(R.anim.custom_in,0 ); setContentView(R.layout.activity_custom_switching); } public void back (View view) { finish(); overridePendingTransition(0 , R.anim.custom_out); } @Override public void onBackPressed () { super .onBackPressed(); overridePendingTransition(0 , R.anim.custom_out); } }
2.使用style的方式定义Activity的切换动画 貌似问题很多
自定义 View 动画 对于 View 动画,建议采用 XML 来定义动画,因为 XML 格式的动画可读性更好。
需要继承 Animation 这个抽象类,并重写 initialize() 和 applyTransformation()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public class Rotate3dAnimation extends Animation { private final float mFromDegrees; private final float mToDegrees; private final float mCenterX; private final float mCenterY; private final float mDepthz; private final boolean mReverse; private Camera mCamera; public Rotate3dAnimation (float mFromDegrees, float mToDegrees, float mCenterX, float mCenterY, float mDepthz, boolean mReverse) { this .mFromDegrees = mFromDegrees; this .mToDegrees = mToDegrees; this .mCenterX = mCenterX; this .mCenterY = mCenterY; this .mDepthz = mDepthz; this .mReverse = mReverse; } @Override public void initialize (int width, int height, int parentWidth, int parentHeight) { super .initialize(width, height, parentWidth, parentHeight); mCamera = new Camera (); } @Override protected void applyTransformation (float interpolatedTime, Transformation t) { final float fromDegrees = mFromDegrees; float degrees = fromDegrees+((mToDegrees-fromDegrees)*interpolatedTime); final float centerX = mCenterX; final float centerY = mCenterY; final Camera camera = mCamera; final Matrix matrix = t.getMatrix(); camera.save(); if (mReverse){ camera.translate(0.0f ,0.0f ,mDepthz*interpolatedTime); }else { camera.translate(0.0f ,0.0f ,mDepthz*(1.0f -interpolatedTime)); } camera.rotateY(degrees); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX,-centerY); matrix.postTranslate(centerX,centerY); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Rotate3dAnimation rotate3dAnimation = new Rotate3dAnimation (0 ,360 ,100 ,100 ,100 ,true );rotate3dAnimation.setDuration(2000 ); rotate3dAnimation.setRepeatCount(1 ); rotate3dAnimation.setFillAfter(true ); rotate3dAnimation.setAnimationListener(new Animation .AnimationListener() { @Override public void onAnimationStart (Animation animation) { Log.e(TAG,"onAnimationStart" ); } @Override public void onAnimationEnd (Animation animation) { Log.e(TAG,"onAnimationEnd" ); } @Override public void onAnimationRepeat (Animation animation) { Log.e(TAG,"onAnimationRepeat" ); } }); tv.startAnimation(rotate3dAnimation);
备注
欢迎关注微信公众号:非也缘也