recyclerView 进阶知识

作者: nothingwxq | 来源:发表于2016-12-10 15:57 被阅读447次

    一 初级篇

    1. 请参照csdn上我的两篇:

    a android 5.0新特性 RecyclerView使用初级
    b Group分组列表的实现 RecyclerView ,实现不同类型的item组合列表

    二 进阶知识点:

    1. 设置Item的间距

    public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
       private final int mLeft;
       private final int mTop;
       private final int mRight;
       private final int mBottom;
    
       /**
        * @param left   padding in pixel
        * @param top    padding in pixel
        * @param right  padding in pixel
        * @param bottom padding in pixel
        */
       public SpaceItemDecoration(int left, int top, int right, int bottom) {
           mLeft = left;
           mTop = top;
           mRight = right;
           mBottom = bottom;
       }
    
       @Override
       public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
           outRect.set(mLeft, mTop, mRight, mBottom);
       }
    }
    

    2. 设置Item的分割线:

    参考 http://blog.csdn.net/cjm2484836553/article/details/53439751
    其实很简单,就是在每个item下面绘制一条带颜色的矩形即为分割线。

    public class MyDeviderDecoration extends RecyclerView.ItemDecoration {  
            private int mydevider;  
            private Paint dividerPaint;  
      
            public MyDeviderDecoration(Context context) {  
                dividerPaint = new Paint();  
                //设置分割线颜色  
                dividerPaint.setColor(context.getResources().getColor(R.color.colorAccent));  
                //设置分割线宽度  
                mydevider = context.getResources().getDimensionPixelSize(R.dimen.divider_bottom);  
            }  
          
            @Override  
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {  
                super.getItemOffsets(outRect, view, parent, state);  
                outRect.bottom = mydevider;  
            }  
     
            @Override  
            public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {  
                int childCount = parent.getChildCount();  
                int left = parent.getPaddingLeft();  
                int right = parent.getWidth() - parent.getPaddingRight();  
      
                for (int i = 0; i < childCount - 1; i++) {  
                    View view = parent.getChildAt(i);  
                    float top = view.getBottom();  
                    float bottom = view.getBottom() + mydevider;  
                    c.drawRect(left, top, right, bottom, dividerPaint);  
                }  
            }  
        }  
    

    3. 如何在recyclerView 中使用 MVVM + DataBinding

    将VM放在holder就好。

    @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == VIEW_TYPE_NORMAL) {
             ...
            } else {
                //更多 
             MoreItemVM viewModel = new ListMoreItemVM(...);
             // 初始化binding
             binding = BindingUtils.inflate(...)
                ...
                binding.setViewModel(viewModel);
                return new ViewHolder(binding.getRoot(), viewModel, binding);
            }
    
        }
    
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            //
            if (getItemViewType(position) == VIEW_TYPE_NORMAL) {
                holder.setData(...);
            } else {
                holder.setData(...);
            }
            holder.mBinding.executePendingBindings();
        }
    
        @Override
        public int getItemViewType(int position) {
            if (position < getItemCount() - 1) {
                return VIEW_TYPE_NORMAL;
            } else {
                return VIEW_TYPE_MORE;
            }
        }
    
    
        public static class ViewHolder extends RecyclerView.ViewHolder {
    
            private ListItemVM mItemViewModel;
            private ListMoreItemVM mMoreItemVM;
            public final ViewDataBinding mBinding;
    
            public ViewHolder(View itemView, ListItemVM itemViewModel, ViewDataBinding binding) {
                super(itemView);
                mItemViewModel = itemViewModel;
                mItemViewModel.reset();
                mBinding = binding;
            }
    
            public ViewHolder(View itemView, ListMoreItemVM itemViewModel, ViewDataBinding binding) {
                super(itemView);
                mMoreItemVM = itemViewModel;
                mBinding = binding;
    
            }
    
            public void setData(RunningAlbumInfo runningAlbumInfo) {
                mItemViewModel.setData(runningAlbumInfo);
            }
    
            public void setData(Category category) {
                mMoreItemVM.setData(category);
            }
        }
    

    4. 如何dissmiss ViewModel中的popwindow

    这个问题,即是说如何拿到当前选中的item。思路很简单,先拿到holder,然后通过holder拿到对应的VM。恩,其实这里的popwindow该放在adpter中show的,统一的逻辑都该adpter来做,VM只负责展示。

     if (mRecyclerView != null && mLinearLayoutManager != null) {
                int pos = mRecyclerView.getCurrentPosition();
                View view = mLinearLayoutManager.getChildAt(pos);
                if (view != null) {
                    ListAdapter.ViewHolder holder =
                            (ListAdapter.ViewHolder) mRecyclerView.getChildViewHolder(view);
                    if (holder.mBinding != null && (holder.mBinding instanceof xxxBinding)
                            && ((xxxBinding) holder.mBinding).getViewModel().isShowing()) {
                        ((xxxBinding) holder.mBinding).getViewModel().dismiss();
                        return true;
                    }
                }
            }
    

    4. 特殊的水平居中、左右两边缩放淡出的列表(Gallery画廊效果):

    这里有几套方案,

    1. 自己实现 较难 (这里主要指复用和缓存及性能上问题)

    2. viewPager 达不到快速滑动,只支持单页

    3. recyclerView + 自定义的LayoutManager 居中显示还有些问题(回弹和状态保存一不小心crash)自定义LayoutManager 实现弧形以及滑动放大效果RecyclerView http://www.jianshu.com/p/7bb7556bbe10

    4. recyclerView + LinearSnapHelper 使用RecyclerView实现Gallery画廊效果(http://www.jianshu.com/p/85bf072bfeed

    5. recyclerViewPager 三方框架 左右view将中间的view裁剪掉了,这是和viewPager相似的问题,绘制Item的时候存在顺序,需要自己动态调试下

    三 使用recyclerView 的 可能出现bug

    bug 1.https://code.google.com/p/android/issues/detail?id=77846

    该问题现在还没有解决。本人是在recyclerView 从内存中重启的时候 ,想保存一个排序和原始数据恢复位置时遇到。

    这里特别指出fragment的生命周期:onCreateView -> onViewCreated -> onActivityCreated -> onViewStateRestored-> onStart -> onResume

    我在这里调了整整一天,都出现google的issue。原来初始化的基类,在onViewCreated中调用,让我造成了这个isssue,重新异步请求刷新了一遍数据。
    基本上看stackoverflow和issue下面的回答,有帮助的大意是:recyclerView 的数据刷新不同步(导致滚动位置无法定位或调用scrollToPosition时不同步)。解决方法是检查下有木有重复的比较连续刷新数据,刷新数据和定位几乎同时调用。

    bug 2 滑动问题,见第一篇文章。

    http://www.jianshu.com/p/4535442d568f
    该文中已提出一个workaround

    3 这个坑,是我自己挖的。

    这里由于产品需要,recyclerView的item的高度为动态的wrap_content(建议不要使用,recyclerView由于得不到具体宽高,会多次调用getView方法),又要求recyclerView的item进行折叠。当recyclerView的数据项不满一屏时,且此时recyclerView的item由展开到折叠,此时存在视觉上的ui缓存。即该折叠项依然占据展开式的位置。此时,进行点击事件或滑动事件时,缓存的数据消失。 而采用stackoverflow上消去drawingcache 的方法没有作用:
    https://www.google.com.sg/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwjo_ue06vnLAhVBYqYKHQESCVkQFggmMAE&url=%68%74%74%70%3a%2f%2f%73%74%61%63%6b%6f%76%65%72%66%6c%6f%77%2e%63%6f%6d%2f%71%75%65%73%74%69%6f%6e%73%2f%31%34%34%31%39%35%39%37%2f%68%6f%77%2d%74%6f%2d%64%69%73%61%62%6c%65%2d%74%68%65%2d%64%72%61%77%69%6e%67%2d%63%61%63%68%65&usg=AFQjCNHua37wKKbmd3802rrE0wWXaTcvcw
    在listView或此处,我使用的workaround均为Handler post方法解决。

    4 recyclerview notifyitemchanged blink

    刷新单个item的时候,出现闪屏现象。(比较常见的是,item做动画时,就存在这个问题)
    1 http://stackoverflow.com/questions/29873859/how-to-implement-itemanimator-of-recyclerview-to-disable-the-animation-of-notify
    2 http://stackoverflow.com/questions/29331075/recyclerview-blinking-after-notifydatasetchanged
    这个查了网上的一些方案,对我起作用的ItemAnimator animator = recyclerView.getItemAnimator();
    if (animator instanceof SimpleItemAnimator) {
    ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
    }

    相关文章

      网友评论

        本文标题:recyclerView 进阶知识

        本文链接:https://www.haomeiwen.com/subject/hgqumttx.html