对RecyclerView Item做动画
来源:互联网 发布:javascript 构造函数 编辑:程序博客网 时间:2024/06/05 08:11
对RecyclerView Item做动画
对RecyclerView Item做动画,刚刚开始研究的时候一些坑,在这里把一些设计思路分享出去
添加动态位移,静态位移,缩放等动画,保证了动画状态的平滑衔接
效果图:
我的Github,Demo下载
RecyclerView,ListView这些具有Item复用性的View,想要对其Item做动画,需要注意以下几点:
1,如果要一点击,让所有Item做动画的效果。例如,上图的编辑和取消,这样的动态动画。可以对所有ViewHolder中的View直接做动画。
但是需要在onBindViewHolder方法中对复用的item做静态动画,保证动画状态的平滑衔接。
2,每一个Item的特有属性,例如,上图checkbox的选中状态,都需要把状态字段放到对应的Java bean中, 并在onBindViewHolder方法从java bean取出状态值,设置到view里。
首先,对一些细节进行分析:
如何设计一个自定义View,来让他可以自己移动,做动画起来?
1,首先,创建一个View,他是RecyclerView Item的根布局:
public class SlideRelativeLayout extends RelativeLayout { public static final String TAG = SlideRelativeLayout.class.getSimpleName(); private CheckBox mCheckBox; private RelativeLayout mContentSlide; private int mOffset; public SlideRelativeLayout(Context context) { super(context); } public SlideRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } public SlideRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onFinishInflate() { super.onFinishInflate(); mCheckBox = (CheckBox) findViewById(R.id.item_checkbox); mContentSlide = (RelativeLayout) findViewById(R.id.item_content_rl); setOffset(35); } public void setOffset(int offset) { mOffset = (int) (getContext().getResources().getDisplayMetrics().density * offset + 0.5f); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void openAnimation() { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setIntValues(0, 1); valueAnimator.setDuration(300); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float fraction = valueAnimator.getAnimatedFraction(); int endX = (int) (-mOffset * fraction); doAnimationSet(endX, fraction); } }); valueAnimator.start(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void closeAnimation() { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setIntValues(0, 1); valueAnimator.setDuration(150); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float fraction = valueAnimator.getAnimatedFraction(); int endX = (int) (-mOffset * (1 - fraction)); doAnimationSet(endX, (1 - fraction)); } }); valueAnimator.start(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void doAnimationSet(int dx, float fraction) { mContentSlide.scrollTo(dx, 0); mCheckBox.setScaleX(fraction); mCheckBox.setScaleY(fraction); mCheckBox.setAlpha(fraction * 255); } public void open() { mContentSlide.scrollTo(-mOffset, 0); } public void close() { mContentSlide.scrollTo(0, 0); } }
这里,在View树创建完毕之后找到我们需要做动画的子View:
@Override protected void onFinishInflate() { super.onFinishInflate(); mCheckBox = (CheckBox) findViewById(R.id.item_checkbox); mContentSlide = (RelativeLayout) findViewById(R.id.item_content_rl); setOffset(35); }
然后,设计4个方法,分别为:动态的打开动画,动态的关闭动画,静态的打开动画,静态的关闭动画。
@TargetApi(Build.VERSION_CODES.HONEYCOMB) public void openAnimation() { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setIntValues(0, 1); valueAnimator.setDuration(300); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float fraction = valueAnimator.getAnimatedFraction(); int endX = (int) (-mOffset * fraction); doAnimationSet(endX, fraction); } }); valueAnimator.start(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void closeAnimation() { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setIntValues(0, 1); valueAnimator.setDuration(150); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float fraction = valueAnimator.getAnimatedFraction(); int endX = (int) (-mOffset * (1 - fraction)); doAnimationSet(endX, (1 - fraction)); } }); valueAnimator.start(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void doAnimationSet(int dx, float fraction) { mContentSlide.scrollTo(dx, 0); mCheckBox.setScaleX(fraction); mCheckBox.setScaleY(fraction); mCheckBox.setAlpha(fraction * 255); } public void open() { mContentSlide.scrollTo(-mOffset, 0); } public void close() { mContentSlide.scrollTo(0, 0); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void doAnimationSet(int dx, float fraction) { mContentSlide.scrollTo(dx, 0); mCheckBox.setScaleX(fraction); mCheckBox.setScaleY(fraction); mCheckBox.setAlpha(fraction * 255); }
对子View做动画我采取的策略是:使用属性动画,在每一贞动画里获取到对应的值,对子View做相应的动画,例如:动态的打开动画。
onAnimationUpdate方法,显示每一贞动画都会回调一次
@TargetApi(Build.VERSION_CODES.HONEYCOMB) public void openAnimation() { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setIntValues(0, 1); valueAnimator.setDuration(300); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float fraction = valueAnimator.getAnimatedFraction(); int endX = (int) (-mOffset * fraction); doAnimationSet(endX, fraction); } }); valueAnimator.start(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void doAnimationSet(int dx, float fraction) { mContentSlide.scrollTo(dx, 0); mCheckBox.setScaleX(fraction); mCheckBox.setScaleY(fraction); mCheckBox.setAlpha(fraction * 255); }
这样RecylerView 带有动态动画和静态动画的View就设计好了。
2,在bind方法中使用静态动画,动态动画对外提供方法调用:
private class SlideViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private SlideRelativeLayout mSlideRelativeLayout; private CheckBox mCheckBox; private ItemBean mItemBean; public SlideViewHolder(View itemView) { super(itemView); mSlideRelativeLayout = (SlideRelativeLayout) itemView.findViewById(R.id.item_root); mCheckBox = (CheckBox) itemView.findViewById(R.id.item_checkbox); itemView.setOnClickListener(this); } public void bind(ItemBean itemBean) { mItemBean = itemBean; mCheckBox.setChecked(itemBean.isChecked()); switch (mState) { case NORMAL: mSlideRelativeLayout.close(); break; case SLIDE: mSlideRelativeLayout.open(); break; } } public void openItemAnimation() { mSlideRelativeLayout.openAnimation(); } public void closeItemAnimation() { mSlideRelativeLayout.closeAnimation(); }
可以看到静态动画在bind里调用,打开或者关闭是由mState变量决定的。而动态的滑动需要手动调用,那怎么来使用这些动画呢?
动态动画的使用方法:存储所有创建出来的ViewHolder,统一调用动态动画方法。并设置mState变量值,防止滑动时动画不能平滑衔接.
private List<SlideViewHolder> mSlideViewHolders = new ArrayList<>(); public void openItemAnimation() { mState = SLIDE;// for (SlideViewHolder holder : mSlideViewHolders) { holder.openItemAnimation(); } } public void closeItemAnimation() { mState = NORMAL; for (SlideViewHolder holder : mSlideViewHolders) { holder.closeItemAnimation(); } }
而外面又是这样调用的:
private void editItems() { if ("编辑".equals(mRightTV.getText().toString())) { mRightTV.setText("取消"); mSlideAdapter.openItemAnimation(); } else if ("取消".equals(mRightTV.getText().toString())) { mRightTV.setText("编辑"); mSlideAdapter.closeItemAnimation(); } }
总体就是:点击按钮 – 变量ViewHolder集合做动态动画,并设置mState变量 – 手机滑动屏幕走bind方法又是根据mState做静态动画
动画从而平滑的衔接起来
再来看一次效果图:
动态动画起先,设置状态值,引导处理正确的静态动画,RecyclerView item的动画处理是不是变简单了。
还有,对item的特殊数据需要在对应的java bean里设置值,在bind方法取值设置到item中去。
分析就到这里了,小程序一枚。
我的Github
2016年7月01日 1:16:33
- 对RecyclerView Item做动画
- 对RecyclerView Item做动画
- recyclerview item动画
- RecyclerView Item加载动画
- RecyclerView拖拽Item动画
- RecyclerView item刷新动画问题
- recyclerview item的进入动画
- Android RecyclerView 动画展开item显示详情
- 去掉RecyclerView的默认item动画
- RecyclerView 实现item点击水波纹动画
- 对RecyclerView的item添加点击事件
- RecyclerView 对Item的分类操作
- RecyclerView实现Item滑动加载进入动画效果
- RecyclerView自定义动画,item飞入,渐隐渐出
- Android RecyclerView Item动画(Checkbox全选、单选)
- RecyclerView实现Item滑动加载进入动画效果
- Recyclerview Item中图片动画错乱问题解决方案
- RecyclerView 分割线和 Item默认增删动画
- NYOJ-37-回文字符串
- Unity实现剧情对话
- 自定义数据类型 --- 类全解(swift2.3)
- iOS下的并行开发
- iOS 地图 MKWebView(在中国是使用高德地图)
- 对RecyclerView Item做动画
- 【Debug Assertion Failed!Expression:_pFirstBlock ==
- Unity3d 中显示 Spine 动画节点 以及设置 帧事件
- 漫谈android系统(6)硬件抽象层kernel分析
- 常用iOS-oc工具方法总结
- SQL语句各个部分的执行顺序
- (数据类型-Number的直接量)JavaScript权威指南笔记4.3
- C# yield return关键字理解
- 移动端Web开发调试之Weinre调试教程