Metail Design之RecyclerView

1.RecyclerView简单设置:

 1 private void initRecyclerView() {
 2         mList = new ArrayList<>();
 3         for (int i = 0; i < 60; i++) {
 4             mList.add(String.format(getString(R.string.lesson),(1+i)+""));
 5         }
 6         setLayoutManget(switchId);
 7         mAdapter = new MainRecyclerAdapter(mList);
 8         mRy.setAdapter(mAdapter);
 9         mRy.setItemAnimator(new DefaultItemAnimator());
10         mAdapter.setItemClickListener(new MainRecyclerAdapter.ItemClickListener() {
11             @Override
12             public void click(View view, int position, String text) {
13                 Toast.makeText(MainActivity.this, "点击--" + text, Toast.LENGTH_SHORT).show();
14                 goActivity(position);
15             }
16         });
17     }

 

rv是高度解耦,可以为他设置LayoutManger,ItemAnimotor,Adaper,Deliver分割线等.

 

2.设置条目添加,移除时可以局部刷新,尽可能优化性能:

 

 3.要使用StaggeredGridLayoutManager

 1).这里模拟给每个Item动态分配高度,记得使用

View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1,parent,false);
这种方式经过看源码发现没有人为的添加到父类的ViewGroup,而是交给RecyclerView自己处理

 

1 @Override
2     public MainViewHold onCreateViewHolder(ViewGroup parent, int viewType) {
3 //        View view = View.inflate(parent.getContext(), android.R.layout.simple_list_item_1, null);//没有添加进parent
4 //        View view = View.inflate(parent.getContext(), android.R.layout.simple_list_item_1, parent);//双重parent
5         View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1,parent,false);
6         return new MainViewHold(view);
7     }

 

 

 2).上面注释两种方式有问题,第一种getLayoutParams参数为空,第二种resoure(android.R.layout.simple_list_item_1)有两个parent,因为查看源码发现root.add(view,params)添加了一次,recyclerview自己又会把item添加进入它之中.

 

 

  3).上面两种方法最终调用的是这个方法,对应的还是第三种方法

 

 4).上一张瀑布流的图:

 

 

 3.RecyclerView设置条目点击事件:

 方式一:采用holder.getAdaperPosition()来获得当前条目的位置信息,这种可以实时获取position信息,包括addItem和remove条目,最好应用于数据集变化的情况.

 
 
 方式二:采用自定义OnClickListener,构造方法时把position传进去,这样position在单独开辟的堆栈里,可以长久存储,最好应用于数据集不发生改变的情况(经过测试,addItem和removeItem后,postion不会实时变化)

 

 监听器: 

 

 

  应用于RecyclerView:

 

 

 4.RecycleView分割线:

 1).初识RecyclerView.ItemDecoration中的 getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 

它是先于onDraw()方法执行的,调用此方法首先会获得条目之间的间隔宽度,Rect的矩形区域.获得条目的偏移量,所有条目都会调用一次该方法.
2)onDraw方法是真正绘制Divider时的方法
 
这里我们先来个简单的,绘制LinearLayoutManager的分割线
首先,可以拿系统的Divider(方便),构造方法传入布局方向

 

 我们可以给divider一个set方法,来动态设置

 

 设置所有item的偏移:

 

 divider绘制的位置:(根据上面)

onDraw()真正的绘制: 

计算边距:

 

 这里以绘制垂直方法为例,也就是长形矩形为例讲解:

 

这里有一点非常需要注意:

 

就是parent.getChildCount()方法是获得当前屏幕一屏的ChildView 数量:

(1).这里绘制的时候child的param要用RecyclerView.LayoutParam的,因为它继承与MaragLayout可以拿到Margin边距

(2).child如果有平移动画这里还要添加动画的距离:Math.round(ViewCompat.getTranslationY(child));
(3).这里记得开始和结束用c.save()和c.restore()来保存画板
(4).这里以child.getBottom)---item5为例说说,获得的值在屏幕上指的是哪里:

 

drawHorazotion()也是同样的原理,再讲讲我们自定义的ItemDecoration怎么应用于recyclerview:

 

这里说说绘制GridView布局分割线:
1).关于偏移量这里就要考虑最后一行和最后一列:

 

 2).这里说说如何判断最后一行最后一列:

 

 3).判断最后一列:

 

 5.RecyclerView像ListView那样添加头和尾布局:

 1).通过看ListView添加头尾的源码,它其中采用了代理模式,添加头尾的时候重新new了一个WrapHeaderListViewAdapter,里面分别用两个List<View> 来存放添加进来的头和尾,getView,getCount等方法还是使用原来adapter,或者加以修饰还是交给子类去实现,所以我们也来模仿这样:

先自己定义一个wrapHeadRecyclerAdapter:

 

 2).模仿着listview重写几个重要的方法:
这里获得数量是把头和尾的也添加进去了

 

3).通过getItemViewType来区分当前条目是什么类型(头,尾,正常条目)

 

 记得这里的mAdapter.getItemViewType(adjPosition)返回的是原来的正常Item,位置也是从0开始的
4).onCreateViewHolder()方法里的头尾位置new出来的hold只要是配合框架使用,其实并没什么用,viewhold的目的主要是目的是复用,而头尾直接是addView就添加进来了,不存在大量复用情况

 

5).onBindViewHolder

 

 6).使用还是跟平常rv一样使用,wrapheadrecyclerview使我们偷偷做的

 

 效果图:

 

 6.RecyclerView添加拖拽和侧滑:

 1).添加拖拽和侧滑需要用到一个ItemTouchHelper,以及ItemTouchHelper.Callback:

1 getMovementFlags()方法

 

 onMove()方法

onSwiped()方法

 isLongPressDragEnabled()方法:

onSelectedChanged()方法:

 clearView()方法:

onChildDraw()方法:

 2).两个不同的类之间通信,采用Interface接口做桥梁,很好的降低耦合:

 

public QQAdapter(List<QQMessage> list, StartDragListener startDragListener) {
        this.list = list;
        mStartDragListener =startDragListener;
    }

holder.iv_logo.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction()==MotionEvent.ACTION_DOWN){
                    mStartDragListener.onStartDrag(holder);
                }
                return false;
            }
        });

例如:这里QQAdapter相与外界通信,通过StartDragListener 接口,把图标iv_logo按下移动时,让ItemTouchHelper调用startDrag()方法

/**
 * 监听Viewhold.icon按下上下拖拽的监听
 */
public interface StartDragListener {
    void onStartDrag(RecyclerView.ViewHolder viewHolder);
}

 在Activity中这样实现:

 

 3).ItemTouchHelper.CallBack需要把他的拖拽和侧滑回调给QQAdapter,来改变数据集的变化和视图的变化,这里通信就只有CallBack与QQAdapter,所以可以通过ItemTouchMoveListener接口来回调出去,QQAdapter来实现接口,分别进行数据的更新和试图的变化:
MyCallBack中:

 

 QQAdaper中:

 

 都是调用的notify方法

 

效果图如下:

 

 

 注意:

 如图:

 

原文地址:https://www.cnblogs.com/jeffery336699/p/9295360.html