Android——RecyclerView入门学习之LayoutManager(二)

96
英勇青铜5
2016.10.19 10:39* 字数 1506

LayoutManager是一个抽象类,有3个子类:

  • LinearLayoutManager 线性布局管理器
  • GridLayoutManager 表格布局管理器
  • StaggeredGridLayoutManager 瀑布流布局管理器

3个布局管理器,之前都是很简单地使用,了解的并都算不多。学习下每个布局管理器中常用的方法,同时了解一下涉及思路,也为以后学习自定义LayoutManager先打点基础


1.LinearLayoutManager 线性布局管理器 <p>

线性布局使用频率很高,几乎每个应用都会有列表,基本都会用到。


1.1 构造方法 <p>

有3个构造方法:

  1. LinearLayoutManager(Context context)
  2. LinearLayoutManager(Context context,int orientation,boolean reverseLayout)
  3. LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,int defStyleRes)

第一个构造方法内部调用了第二个构造方法,第二个构造方法参数的含义:

  • Context context :上下文,初始化时,构造方法内部加载资源用
  • int orientation :方向,垂直和水平,默认为垂直
  • boolean reverseLayout:是否倒序,设置为True,从最后一个item开始,倒序加载。此时,RecyclerView第一个item是添加进Adapter中的最后一个,最后一个item是第一个加进Adapter的数据,RecyclerView会自动滑到末尾

将reverseLayout设置为true:

倒序展示,RecycelrView自动滑动到最后

但此时的设置的分割线如果考虑的不够全面,就会受到影响。具体的使用场景不清楚。如果只是为了让数据倒序展示,而RecyclerView还是从头开始而不自动滑动末尾,可以在数据添加进Adapter前,将集合内的数据进行倒序处理

orientation,也可以通过manger.setOritation()设置
reverseLayout,也可以通过manager.setReverseLayout()设置


第3个构造方法,可以使用自定义属性,根据属性优先级选择在不同的时机,根据需求来使用不同的样式,目前使用不多,详细的内容可以查看Android自定义View构造函数详解


1.2 setStackFromEnd(boolean stackFromEnd) <p>

源码中的注释:

When stack from bottom is set to true, the list fills its content starting from the bottom of the view.

当从堆底部开始展示设置为true时,列表便会从底部开始展示内容

设置为true时,RecycelrView会自动滑倒尾部,直到最后一条数据完整展示

setStackFromEnd(true)时

这个方法和manager.setReverseLayout(true)共同点就是都自动滑动尾部,RecyclerView默认会展示末尾的item。差别在于,manager.setStackFromEnd(true)不会影响内部的数据顺序,怎么添加进Adapter的,就怎么展示


1.3scrollToPosition(int position)滑动到指定item<p>

使用也特简单,manager.scrollToPosition(15)

scrollToPosition(15)

方法中需要的positionadapter position,就是在Adapter中,item实际的positon

这个方法在刚刚初始化LayoutManger时,就可以使用,此时还没有向Adapter中添加数据

方法源码:

/**
 *Scroll the RecyclerView to make the position visible. 
 *
 *Note that scroll position change will not be reflected until the next layout call.</p>
 *
 * @param position Scroll to this adapter position
 * @see #scrollToPositionWithOffset(int, int)
 */
@Override
public void scrollToPosition(int position) {
    mPendingScrollPosition = position;
    mPendingScrollPositionOffset = INVALID_OFFSET;
    if (mPendingSavedState != null) {
        mPendingSavedState.invalidateAnchor();
    }
    requestLayout();
}

方法将传递进来的positon赋值给了mPendingScrollPosition,并调用了requestLayout()方法。感觉是在布局chidlView时,进行了回调处理

暂时只是简单看了一眼源码,里面具体的过程比较复杂,没有深挖

mPendingScrollPositionOffset = INVALID_OFFSET这行代码是设置偏移量的,INVALID_OFFSET默认为Integer.MIN_VALUE


这个方法还有一个类似的方法scrollToPositionWithOffset(int position, int offset)

源码中两个方法的差别在于mPendingScrollPositionOffset = offset

将之前的manager.scrollToPosition(15)换成manager.scrollToPositionWithOffset(15,30),同样会调到adapter positoin15item,但整个RecycelrView中的内容,向下偏移了30 px

设置偏移量为30


1.4 获取当前RecyclerView首尾可见item的adapter positon方法 <p>

方法 作用
findFirstVisibleItemPosition() 返回当前RecycelrView中第一个可见的itemadapter postion
findLastVisibleItemPosition() 返回当前RecycelrView中最后一个可见的itemadapter postion
findFirstCompletelyVisibleItemPosition() 返回当前RecycelrView中第一个完整可见的itemadapter postion
findLastCompletelyVisibleItemPosition() 返回当前RecycelrView中最后一个完整可见的itemadapter postion

方法1:findFirstVisibleItemPosition()方法2:findFirstCompletelyVisibleItemPosition()的差别在于:在RecyclerView中,第一个item_A只是露出一点点,并没有完全展示,item_BA下方的一个item,完全展示在屏幕上,方法1返回的是item_Aadapter position方法2返回item_Badapter position

例如:

设置偏移量为30

  • findFirstVisibleItemPosition():14
  • findFirstCompletelyVisibleItemPosition():15
  • findLastVisibleItemPosition():33
  • findLastCompletelyVisibleItemPosition():32

这4个方法,只有当RecyclerView在屏幕展示出来后,才能得到正常的返回值,否则都是-1

LinearLayoutManager暂时就先学习这几个常用的方法


2. GridLayoutManager 表格布局管理器 <p>

继承之LinearLayoutManager,在需要使用instanceofLinearLayoutManager做判断时,需要注意

GridLayoutManager同样也有3个构造方法,由于是继承LiearLayoutMnager,使用起来差别不大,构造方法内使用了super()方法来直接调用了父类的构造方法:

代码:

 /**
  * Creates a vertical GridLayoutManager
  *
  * @param context Current context, will be used to access resources.
  * @param spanCount The number of columns in the grid
  */
public GridLayoutManager(Context context, int spanCount) {
    super(context);
    setSpanCount(spanCount);
}
  • spanCount : 列数

根据方法的注释,可以知道,默认情况下,GridLayoutManager是垂直的

在方法内,列数是调用setSpanCount(spanCount)进行设置;相应的,getSpanCount()可以得到列数


注意:
setStackFromEnd()不支持GridLayoutManager(),但支持setReverseLayout(boolean)方法

常用的方法在LinearLayoutManager()提过了,其他的方法暂时先放一下


3.StaggeredGridLayoutManager 瀑布流管理器<p>

简单使用:

public class LMActivity extends AppCompatActivity {

    private RecyclerView rv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lm);
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        rv = (RecyclerView) findViewById(R.id.rv_lm_activity);
        //瀑布流布局管理器
        StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
        rv.setLayoutManager(manager);
        //添加边距
        rv.addItemDecoration(new RVItemDecoration(16));
        //适配器
        RecyclerViewAdapter adapter  = new RecyclerViewAdapter(rv,R.layout.id_rv_item_layout,R.id.tv__id_item_layout);
        rv.setAdapter(adapter);
        //添加数据
        List<String> dataList = new ArrayList<>();
        final String res = "英勇青铜5";
        for (int i = 0 ; i < 50; i ++){
            int num = (int)(Math.random() * 20 +1);
            StringBuilder stringBuilder = new StringBuilder();
            for (int j = 0 ; j < num; j ++){
                stringBuilder.append(res,0,res.length());
            }
            dataList.add(stringBuilder.toString());
            stringBuilder.delete(0,stringBuilder.length());
        }
        adapter.setData(dataList);
    }
     @Override
    protected void onDestroy() {
        super.onDestroy();
        rv.setAdapter(null);
    }
}

Item布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv__id_item_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        android:textAllCaps="false"
        android:textColor="@android:color/white"
        android:textSize="20sp" />

</LinearLayout>

效果:

瀑布流

使用这3个布局管理器,差不多90%的需求都能满足吧,自定义LayoutManager打算放在学习过RecycelrView的工作流程后再学习


4. 最后 <p>

都是非常基础的使用,几个方法的简单说明,非常基础,并没有啥知识点。还真是照应标题,首尾呼应,符合入门学习 :(

昨天晚上,看了老罗锤子M1的发布会。作为一个Android开发者,对于Big BangOne Step倒是更感兴趣,尤其Big Bang,感觉会是一个非常不错的学习资料。等代码开源出来后,要是能够学得动代码,也记录一下

本人很菜,有错误请指出

共勉 :)

Android基础学习
Web note ad 1