之前看到系统中每个项目中都定义了N多的XML动画属性,不过我不准备去说动画,因为我之前使用RecyclerView的Item加了一些动画,所以来回顾一下相关的知识点
先看一下可能会用到的属性
attributes | explain |
---|---|
android:interpolator <set> | 可以用于动画的差值器,可以使用默认的差值器,该值必须是对指定插值器的资源的引用如:android:interpolator="@android:anim/decelerate_interpolator" |
android:shareInterpolator <set> | 在使用set标签的时候,如果这个属性等于true那么就是说明你想在所有子元素中共享set标签下的这个插值器 |
android:ordering <set> | 指定此集合中动画的播放顺序。Value:sequentially(按顺序播放这组动画)Value:together (default)(同时播放集合中的动画) |
android:fromAlpha<alpha> | value为float,起始透明度偏移量,0为透明,1.0为不透明 |
android:toAlpha<alpha> | value为float,结束透明度偏移量,0为透明,1.0为不透明 |
android:fromXScale <scale> | value为float,起始的X方向上相对自身的缩放比例,1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍 |
android:toXScale <scale> | value为float, 结束的X方向上相对自身的缩放比例,1.0代表自身无变化 |
android:fromYScale <scale> | value为float,起始的Y方向上相对自身的缩放比例,1.0代表自身无变化 |
android:toYScale <scale> | value为float, 结束的Y方向上相对自身的缩放比例 ,1.0代表自身无变化 |
android:pivotX <scale> | 变化时,起点X轴坐标不变,例如:设置为50%就是X方向坐标上的中点位置,可以是数值、百分数、百分数p |
android:pivotY <scale> | 变化时,起点Y轴坐标不变,例如:设置为50%就是Y方向坐标上的中点位置,可以是数值、百分数、百分数p |
android:fromXDelta <translate> | 起始点X轴坐标,可以是数值、百分数、百分数p |
android:toXDelta <translate> | 结束点X轴坐标,可以是数值、百分数、百分数p |
android:fromYDelta <translate> | 起始点Y轴坐标,可以是数值、百分数、百分数p |
android:toYDelta <translate> | 结束点Y轴坐标,可以是数值、百分数、百分数p |
android:fromDegrees <rotate> | 起始旋转的角度位置,度数为正代表顺时针方向,度数为负值表示逆时针方向 |
android:toDegrees <rotate> | 结束旋转的角度位置,度数为正代表顺时针方向,度数为负值表示逆时针方向 |
android:pivotX <rotate> | 旋转中心的X坐标,可以是数值、百分数、百分数p |
android:pivotY <rotate> | 旋转中心的Y坐标,可以是数值、百分数、百分数p |
android:propertyName <objectAnimator> | 必须设置为String 如:android:propertyName="string" |
android:valueTo <objectAnimator> | 动画属性结束的值,必须设置为float, int, or color |
android:valueFrom <objectAnimator> | 动画属性开始的值必须设置为float, int, or color |
android:duration <objectAnimator> | 动画执行的时间,默认是300毫秒 |
android:startOffset <objectAnimator> | int值 在start()之后,动画延迟的毫秒数 |
android:repeatCount <objectAnimator> | 多少次,重复一个动画。设置为 -1表示无限重复;设置为1 表示动画在初始运行后再重复一次,因此动画总共播放两次;默认值为0 ,表示动画不重复 |
android:repeatMode <objectAnimator> | 这个属性要想生效,那么android:repeatCount 这个值为-1或者为正整数,可以设置两个值,reverse(从结束的位置继续),repeat (从新开始) |
android:valueType<objectAnimator> | 首先是不需要指定颜色的属性,安卓的框架自己会处理,intType指定动画值是整数。floatType (默认)指定动画值是浮点数 |
关于数值、百分数、百分数p的用法。例如:value=20 当前View左上角(X,Y)处,增加20,然后以此为起始点变换;value=20%表示在当前View左上角(X,Y)+自己宽/高的20%做为起始点,然后以此为起始点变换;value=20%p P指的是parent,在当前的左上角(X,Y)加上父控件宽度的20%做为起始点X/Y轴坐标,然后以此为起始点变换。
上面列出了我们在XML常用到的各种动画属性标签的含义,这样就可以进入正题了。
为RecyclerView添加初始动画(LinearLayoutManager)
添加这个动画,我们可以写代码,可以继承ItemAnimator。既然上面介绍了那么多XML属性,那么就添加一个LayoutAnimation来实现吧。
LayoutAnimation是对于某一组控件的操作,就需要一个基本的动画来定义单个控件的动画,而且还可以定义动画的显示顺序和延迟时间。LayoutAnimation可以用在任何ViewGroup上
1.创建动画集合anim/item_animation_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_mediumAnimTime">
<translate
android:fromYDelta="-50%"
android:interpolator="@android:anim/decelerate_interpolator"
android:toYDelta="0" />
<alpha
android:fromAlpha="0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toAlpha="1" />
<scale
android:fromXScale="125%"
android:fromYScale="125%"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="100%"
android:toYScale="100%" />
</set>
2.创建LayoutAnimation anim/layout_animation_down.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_animation_down"
android:delay="20%"
android:animationOrder="normal"/>
android:delay=”20%”
为每个item动画添加一个延时,0%将导致所有item同步运行,100%则让前一个item的动画运行完了下一个item才开始动画。我这里使用的是20%,表示item A的动画运行了20%之后再开始运行B的动画
3.应用LayoutAnimation,可以在代码中也可以在XML中
recyclerView.setLayoutManager(linearLayoutManager);
LayoutAnimationController animation = AnimationUtils.
loadLayoutAnimation(this, R.anim.layout_animation_down);
recyclerView.setLayoutAnimation(animation);
或者
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/layout_animation_down"/>
效果如下:
这里的RecyclerView和NestedScrollView一起用时,会感觉划不动,需要禁止NestedScrollView的滑动,调用一个方法即可解决冲突recyclerView.setNestedScrollingEnabled(false);
4.从底部,从左侧,从右侧进入的动画基本是一样的。改变 translate 的方向就可以了,依次是
<translate
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromYDelta="40%p"
android:toYDelta="0"/>
<translate
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="-50%p"
android:toXDelta="0"/>
<translate
android:interpolator="@android:anim/decelerate_interpolator"
android:fromXDelta="50%p"
android:toXDelta="0"/>
如果加载数据的时候,需要Item的动画重新展示一遍可以调用
recyclerView.scheduleLayoutAnimation();
为RecyclerView添加动画(GridLayoutManager)
如果是GridLayout添加动画,那么可能比上面稍微复杂一些
- 先定义anim/grid_layout_animation.xml
<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_animation_down"
android:animationOrder="normal"
android:columnDelay="20%"
android:directionPriority="column"
android:direction="top_to_bottom|left_to_right"
android:rowDelay="20%" />
- android:animationOrder :控制动画内容的顺序
可以设置三个值,分别是normal(引用的@anim里面怎么定义,那么动画顺序它就怎么执行) reverse (与normal执行方向相反)以及 random(随机的顺序) - android:directionPriority:加载动画设置方向优先级column(列优先)row(行优先)none(默认)
- android:columnDelay:每列上的动画延迟
- android:rowDelay:每行上的动画延迟
android:direction=”top_to_bottom|left_to_right” 动画执行的方向,动画将从左上角开始,移动到右下角
如果定义为top_to_bottom|right_to_left,那么将从右上角开始移动到左下角。和上面一样,在代码中设置
GridLayoutAnimationController animation = (GridLayoutAnimationController) AnimationUtils.
loadLayoutAnimation(this, R.anim.grid_layout_animation);
recyclerView.setLayoutAnimation(animation);
那么会报错,因为LayoutAnimationController中只能识别LayoutAnimation,要想解决此问题。要重写RecyclerView,网上已经有人给出了解决办法。
我这里贴一下代码。
public class GridRecyclerView extends RecyclerView {
/** @see View#View(Context) */
public GridRecyclerView(Context context) { super(context); }
/** @see View#View(Context, AttributeSet) */
public GridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); }
/** @see View#View(Context, AttributeSet, int) */
public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
@Override
protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params,
int index, int count) {
final LayoutManager layoutManager = getLayoutManager();
if (getAdapter() != null && layoutManager instanceof GridLayoutManager){
GridLayoutAnimationController.AnimationParameters animationParams =
(GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;
if (animationParams == null) {
// If there are no animation parameters, create new once and attach them to
// the LayoutParams.
animationParams = new GridLayoutAnimationController.AnimationParameters();
params.layoutAnimationParameters = animationParams;
}
// Next we are updating the parameters
// Set the number of items in the RecyclerView and the index of this item
animationParams.count = count;
animationParams.index = index;
// Calculate the number of columns and rows in the grid
final int columns = ((GridLayoutManager) layoutManager).getSpanCount();
animationParams.columnsCount = columns;
animationParams.rowsCount = count / columns;
// Calculate the column/row position in the grid
final int invertedIndex = count - 1 - index;
animationParams.column = columns - 1 - (invertedIndex % columns);
animationParams.row = animationParams.rowsCount - 1 - invertedIndex / columns;
} else {
// Proceed as normal if using another type of LayoutManager
super.attachLayoutAnimationParameters(child, params, index, count);
}
}
}
这是因为RecyclerView是使用LayoutManager来布局自己的子view的,它并不知道LayoutManager如何放置子view。因此RecyclerView不知道到底该把AnimationParameter应用到list上还是grid上,而默认是list。为了修复这个问题我们需要一个自定义的RecyclerView,让它知道GridLayoutManager的存在。
那么效果图如下:
文章部分内容参考了:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0819/8397.html