Android RecyclerView 动画展开item显示详情

简介:

stackoverflow上看到这个问题,答主给了个demo 
http://stackoverflow.com/questions/27446051/recyclerview-animate-item-resize 
看懂了之后发个博,记录一下,刚开始看别人代码好难受,就这么3个文件看了一晚上。。

效果如下 

res文件 
main_activity文件就是一个recyclerview 
main_item是两个textview 一个标题一个详细信息

MainActivity就是加载了一个RecyclerView

public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); final RecyclerView rv = (RecyclerView) findViewById(R.id.rv); final LinearLayoutManager layoutManager = new LinearLayoutManager(this); rv.setLayoutManager(layoutManager); final MainAdapter adapter = new MainAdapter(); rv.setAdapter(adapter); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

MainAdapter中new了一个keepOne对象,点进去看这个类,有两个方法:bind和toggle,其中的bind是在MainAdapter中的onBindViewHolder()方法中调用,而toggle是响应viewholder的点击事件

public static class KeepOneH<VH extends RecyclerView.ViewHolder & Expandable> { // opened为-1表示所有item是关闭状态,open为pos值的表示pos位置的item为展开的状态 private int _opened = -1; public void bind(VH holder, int pos) { if (pos == _opened) // 3 // 直接显示expandView 无动画 ExpandableViewHoldersUtil.openH(holder, holder.getExpandView(), false); else // 直接关闭expandView 无动画 ExpandableViewHoldersUtil.closeH(holder, holder.getExpandView(), false); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
@SuppressWarnings("unchecked")
//        响应点击事件的方法
        public void toggle(VH holder) { // 如果点击的就是开着的item,就关闭该item并把opened置-1 // ???TODO if (_opened == holder.getPosition()) { _opened = -1; // 关闭expandView 有动画 ExpandableViewHoldersUtil.closeH(holder, holder.getExpandView(), true); } // 如果点击其他本来关闭着的item,则把opened值换成当前pos,把之前开的item给关掉 else { int previous = _opened; _opened = holder.getPosition(); // 展开expandView 有动画 ExpandableViewHoldersUtil.openH(holder, holder.getExpandView(), true); // 用动画关闭之前的item final VH oldHolder = (VH) ((RecyclerView) holder.itemView.getParent()).findViewHolderForPosition(previous); if (oldHolder != null) ExpandableViewHoldersUtil.closeH(oldHolder, oldHolder.getExpandView(), true); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

点进openH和closeH方法进去看

//    4
    public static void openH(final RecyclerView.ViewHolder holder, final View expandView, final boolean animate) { // animate参数为true,则有动画效果 if (animate) { expandView.setVisibility(View.VISIBLE); // 5 // 改变高度的动画,具体操作点进去看 final Animator animator = ViewHolderAnimator.ofItemViewHeight(holder); // 扩展的动画结束后透明度动画开始 animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { final ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(expandView, View.ALPHA, 1); alphaAnimator.addListener(new ViewHolderAnimator.ViewHolderAnimatorListener(holder)); alphaAnimator.start(); } }); animator.start(); } // animate参数为false,则直接设置为可见 else { expandView.setVisibility(View.VISIBLE); expandView.setAlpha(1); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

openH方法接收3个参数, 
第一个是viewholder. 
第二个是展开部分的view,由holder.getExpandView()方法获取。这里定义了一个接口

public static interface Expandable {
        public View getExpandView(); }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

在MainAdapter中传入infos这个Textview

@Override
        public View getExpandView() {
            return infos;
        }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

第三个是一个标记,true时有动画,false时直接设置其展开或者是关闭的状态。所以在bind()方法中调用的openH()都是false,而toggle()中调用的设置为true。

openH方法中 具体动画的操作为ViewHolderAnimator.ofItemViewHeight(holder)

public static Animator ofItemViewHeight(RecyclerView.ViewHolder holder) {
        View parent = (View) holder.itemView.getParent();
        if (parent == null)
            throw new IllegalStateException("Cannot animate the layout of a view that has no parent"); // 测量扩展动画的起始高度和结束高度 int start = holder.itemView.getMeasuredHeight(); holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); int end = holder.itemView.getMeasuredHeight(); // 6 final Animator animator = LayoutAnimator.ofHeight(holder.itemView, start, end); // 设定该item在动画开始结束和取消时能否被recycle animator.addListener(new ViewHolderAnimatorListener(holder)); // 设定结束时这个item的宽高 animator.addListener(new LayoutParamsAnimatorListener(holder.itemView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); return animator; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可以看出 具体展开的动画在LayoutAnimator.ofHeight(holder.itemView, start, end);中,ViewHolderAnimator只是测量参数,设定监听两个监听事件 
1设定在动画开始结束和取消状态下是否可以被回收

public ViewHolderAnimatorListener(RecyclerView.ViewHolder holder) {
            _holder = holder;
        }

        @Override
        public void onAnimationStart(Animator animation) { _holder.setIsRecyclable(false); } @Override public void onAnimationEnd(Animator animation) { _holder.setIsRecyclable(true); } @Override public void onAnimationCancel(Animator animation) { _holder.setIsRecyclable(true); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2.设定在动画结束后view的高和宽分别为warp_content,match_parent.

public static class LayoutParamsAnimatorListener extends AnimatorListenerAdapter { private final View _view; private final int _paramsWidth; private final int _paramsHeight; public LayoutParamsAnimatorListener(View view, int paramsWidth, int paramsHeight) { _view = view; _paramsWidth = paramsWidth; _paramsHeight = paramsHeight; } @Override public void onAnimationEnd(Animator animation) { final ViewGroup.LayoutParams params = _view.getLayoutParams(); params.width = _paramsWidth; params.height = _paramsHeight; _view.setLayoutParams(params); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

再深入一层看展开的动画

public class LayoutAnimator {

    public static class LayoutHeightUpdateListener implements ValueAnimator.AnimatorUpdateListener { private final View _view; public LayoutHeightUpdateListener(View view) { _view = view; } @Override public void onAnimationUpdate(ValueAnimator animation) { final ViewGroup.LayoutParams lp = _view.getLayoutParams(); lp.height = (int) animation.getAnimatedValue(); _view.setLayoutParams(lp); } } public static Animator ofHeight(View view, int start, int end) { final ValueAnimator animator = ValueAnimator.ofInt(start, end); animator.addUpdateListener(new LayoutHeightUpdateListener(view)); return animator; } }
  • 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
  • 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

是用ValueAnimator.ofInt生成一系列高度值,然后监听动画的变化,不断设定view的高度值

 

http://blog.csdn.net/gulumi_mmga/article/details/46683437




    本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/5825015.html,如需转载请自行联系原作者


相关文章
|
3月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
78 2
基于Android P,自定义Android开机动画的方法
|
25天前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
2月前
|
Android开发 开发者 索引
Android实战经验之如何使用DiffUtil提升RecyclerView的刷新性能
本文介绍如何使用 `DiffUtil` 实现 `RecyclerView` 数据集的高效更新,避免不必要的全局刷新,尤其适用于处理大量数据场景。通过定义 `DiffUtil.Callback`、计算差异并应用到适配器,可以显著提升性能。同时,文章还列举了常见错误及原因,帮助开发者避免陷阱。
187 9
|
2月前
|
存储 缓存 Android开发
Android RecyclerView 缓存机制深度解析与面试题
本文首发于公众号“AntDream”,详细解析了 `RecyclerView` 的缓存机制,包括多级缓存的原理与流程,并提供了常见面试题及答案。通过本文,你将深入了解 `RecyclerView` 的高性能秘诀,提升列表和网格的开发技能。
68 8
|
3月前
|
存储 Android开发 开发者
Android项目架构设计问题之定义RecyclerView的ViewHolder如何解决
Android项目架构设计问题之定义RecyclerView的ViewHolder如何解决
43 0
|
3月前
|
数据可视化 Java 数据挖掘
Android项目架构设计问题之设置RecyclerView的LayoutManager如何解决
Android项目架构设计问题之设置RecyclerView的LayoutManager如何解决
34 0
|
4月前
|
XML Android开发 UED
Android动画之共享元素动画简单实践
本文介绍Android共享元素动画, 实现两Activity间平滑过渡特定UI元素。通过设置`transitionName`属性和使用`ActivityOptions.makeSceneTransitionAnimation`启动目标Activity实现动画效果。可自定义过渡动画提升体验。
66 0
|
Android开发
Android自定义View,制作饼状图带动画效果
一个简单的自定义view饼状图,加入了动画效果
152 0
Android自定义View,制作饼状图带动画效果