RecyclerViewLayoutManager分析 添加头部尾部

优化版本点击这里

RecyclerView使用也有一段时间了 他的出现是对ListView,GridView的进化,

LayoutManager负责布局Adpater负责数据处理自带缓存机制,不用开发者过多处理,更多的关注业务逻辑就行
更加灵活,但是需要开发者多多的操作相关事件,比如点击事件那就需要自定义接口,没有类似于ListView的addHaedView等方法在使用中用的多的就是有添加头部尾部 加载更多 下拉刷新(可以和系统的refreshlayout)一起使用

项目中我用的是easyRecyclerView 开源项目(自行github 挺好用) 主要是加载更多和下拉刷新实现了 添加头部尾部貌似不行 用这个LayoutManager来辅助实现 完全可以 因为EasyRecyclerView的加载更多等等解耦很好 都是Adpater来处理数据 解耦的好处 互不影响 真是其实厉害

正题
前面看到一篇博客
源地址
http://m.blog.csdn.net/blog/oushangfeng123/47435867

讲用LayoutManager来实现RecycleView的头部尾部添加,特意实现了一遍 它里面稍微分析了一下 看了一下源码 我就不分析了 看他的原帖去吧

先看个效果 都是添加了头部和尾部

GIF.gif

上Activity代码

public class RecyclerViewMainActivity extends ActionBarActivity {

private android.widget.Button bt1;
private android.widget.Button bt2;
private android.widget.Button bt3;
private RecyclerView rcv;
private GridLayoutManager gridLayoutManager;
private StaggeredGridLayoutManager staggeredGridLayoutManager;
List<String> lists=new ArrayList<String>();
private LinearLayoutManager linearLayoutManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_recycler_view_main);
    this.rcv = (RecyclerView) findViewById(R.id.rcv);

    this.bt3 = (Button) findViewById(R.id.bt3);
    this.bt2 = (Button) findViewById(R.id.bt2);
    this.bt1 = (Button) findViewById(R.id.bt1);

    bt2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            gridLayoutManager = new GridLayoutManager(RecyclerViewMainActivity.this, 2);
            lists.clear();
            for(int i=0 ; i<20 ; i++){
                lists.add("123"+i);
            }
            RecycleViewGridAdapter recycleViewAdapter = new RecycleViewGridAdapter(lists);
            LayoutInflater layoutInflater = getLayoutInflater();
            View view = layoutInflater.inflate(R.layout.item_top, null);
            recycleViewAdapter.addHeadView(view);
            View view1 = layoutInflater.inflate(R.layout.item_foot, null);
            recycleViewAdapter.addFootView(view1);

            //如果添加了头部或者尾部 就需要做相关的SpanSize的修改
            recycleViewAdapter.setChangeGridLayoutManager(new RecycleViewGridAdapter.ChangeGridLayoutManagerSpance() {
                @Override
                public void change(final int size, final boolean isAddHead, final boolean isAddFoot) {
                    gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                        @Override
                        public int getSpanSize(int position) {
                            int spanSzie = 1;
                            if (isAddHead) {
                                if (position == 0) {
                                    spanSzie = gridLayoutManager.getSpanCount();
                                }
                            }

                            if (isAddFoot) {
                                if (position == size) {
                                    spanSzie = gridLayoutManager.getSpanCount();
                                }
                            }
                            return spanSzie;
                        }
                    });
                }
            });
            rcv.setLayoutManager(gridLayoutManager);
            rcv.setAdapter(recycleViewAdapter);
        }
    });


    bt3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            staggeredGridLayoutManager=new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
            lists.clear();
            for(int i=0 ; i<20 ; i++){
                lists.add("123"+i);
            }
            RecycleViewStageredAdapter recycleViewStageredAdapter = new RecycleViewStageredAdapter(lists);
            recycleViewStageredAdapter.addHeadView(R.layout.item_top);
            recycleViewStageredAdapter.addFootView(R.layout.item_top);

            rcv.setLayoutManager(staggeredGridLayoutManager);
            rcv.setAdapter(recycleViewStageredAdapter);
        }
    });

    bt1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
             linearLayoutManager=new LinearLayoutManager(RecyclerViewMainActivity.this);
            linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

            lists.clear();
            for(int i=0 ; i<20 ; i++){
                lists.add("123"+i);
            }
            RecycleviewLinearAdapter recycleviewLinearAdapter=new RecycleviewLinearAdapter(lists);

            LayoutInflater layoutInflater = getLayoutInflater();
            View view = layoutInflater.inflate(R.layout.item_top, null);
            recycleviewLinearAdapter.addHeadView(view);
            View view1 = layoutInflater.inflate(R.layout.item_foot, null);
            recycleviewLinearAdapter.addFootView(view1);

            rcv.setLayoutManager(linearLayoutManager);
            rcv.setAdapter(recycleviewLinearAdapter);

        }
    });
}
}    

然后是各个ViewHolder 整体结构图

Paste_Image.png

RecycleviewLinearAdapter 代码

public class RecycleviewLinearAdapter<T> extends RecyclerView.Adapter<LinearViewHolder> {
private static final int TYPE_HEADER = 0, TYPE_ITEM = 1, TYPE_FOOT = 2;
public List<T> mDatas;
private View headView;
private View footView;
private int headViewSize = 0;
private int footViewSize = 0;
private boolean isAddFoot = false;
private boolean isAddHead = false;

public RecycleviewLinearAdapter(List<T> mDatas) {
    this.mDatas = mDatas;
}

public void addHeadView(View view) {
    headView = view;
    headViewSize = 1;
    isAddHead = true;
}

public void addFootView(View view) {
    footView = view;
    footViewSize = 1;
    isAddFoot = true;
}

@Override
public int getItemViewType(int position) {
    int type = TYPE_ITEM;
    if (headViewSize == 1 && position == 0) {
        type = TYPE_HEADER;
    } else if (footViewSize == 1 && position == getItemCount() - 1) {
        //最后一个位置
        type = TYPE_FOOT;
    }
    return type;
}


@Override
public LinearViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = null;
    switch (viewType) {
        case TYPE_HEADER:
            view = headView;
            break;

        case TYPE_ITEM:
            view = View.inflate(parent.getContext(), R.layout.item_icon, null);
            break;

        case TYPE_FOOT:
            view = footView;
            break;
    }
    return new LinearViewHolder(view);
}

@Override
public void onBindViewHolder(LinearViewHolder holder, int position) {
}

@Override
public int getItemCount() {
    return mDatas.size()+headViewSize+footViewSize;
}
}

class LinearViewHolder extends RecyclerView.ViewHolder {
public LinearViewHolder(View itemView) {
    super(itemView);
}
}

RecycleViewGridAdapter 代码

public class RecycleViewGridAdapter<T> extends RecyclerView.Adapter<MyViewHolder> {
private static final int TYPE_HEADER = 0, TYPE_ITEM = 1, TYPE_FOOT = 2;

public List<T> mDatas;
private View headView;
private View footView;
private int headViewSize = 0;
private int footViewSize = 0;
private ChangeGridLayoutManagerSpance changeGridLayoutManager;
private boolean isAddFoot=false;
private boolean isAddHead=false;




public interface ChangeGridLayoutManagerSpance{
    public void change(int size, boolean isAddHead, boolean isAddFoot);
}
//提供接口给 让LayoutManager根据添加尾部 头部与否来做判断 显示头部与底部的SpanSize要在添加头部和尾部之后 
public void setChangeGridLayoutManager(ChangeGridLayoutManagerSpance changeGridLayoutManager){
    this.changeGridLayoutManager=changeGridLayoutManager;
    changeGridLayoutManager.change(getItemCount()-1,isAddHead,isAddFoot);
}

public RecycleViewGridAdapter(List<T> datas) {
    mDatas = datas;
}

public void addHeadView(View view) {
    headView = view;
    headViewSize = 1;
    isAddHead=true;
}

public void addFootView(View view) {
    footView = view;
    footViewSize = 1;
    isAddFoot=true;
}

@Override
public int getItemViewType(int position) {
    int type = TYPE_ITEM;

    if (headViewSize==1 && position == 0) {
        type = TYPE_HEADER;
    } else if (footViewSize==1 && position == getItemCount()-1) {
        //最后一个位置
        type = TYPE_FOOT;
    }
    return type;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = null;
    switch (i) {
        case TYPE_HEADER:
            view = headView;
            break;

        case TYPE_ITEM:
            view = View.inflate(viewGroup.getContext(), R.layout.item_icon, null);
            break;

        case TYPE_FOOT:
            view =footView;
            break;
    }
    return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {

}
@Override
public int getItemCount() {
    return mDatas.size() + headViewSize + footViewSize;
}
}

class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemView) {
    super(itemView);
}
}

RecycleViewStageredAdapter 代码

public class RecycleViewStageredAdapter<T> extends RecyclerView.Adapter<MyViewHolder1>{
private static final int TYPE_HEADER = 0, TYPE_ITEM = 1, TYPE_FOOT = 2;

public List<T> mDatas;
private int headViewid;
private int headViewSize;
private boolean isAddHead;
private int footViewid;
private int footViewSize;
private boolean isAddFoot;

public RecycleViewStageredAdapter(List<T> mDatas) {
    this.mDatas = mDatas;
}

public void addHeadView(int view) {
    headViewid = view;
    headViewSize = 1;
    isAddHead=true;
}

public void addFootView(int view) {
    footViewid = view;
    footViewSize = 1;
    isAddFoot=true;
}

@Override
public MyViewHolder1 onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = null;
    switch (i) {
        case TYPE_HEADER:
            view = LayoutInflater.from(viewGroup.getContext()).inflate(headViewid, viewGroup, false);
            break;

        case TYPE_ITEM:
            view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_icon, viewGroup, false);
            break;

        case TYPE_FOOT:
            view = LayoutInflater.from(viewGroup.getContext()).inflate(footViewid, viewGroup, false);
            break;
    }
    return new MyViewHolder1(view);
}

@Override
public void onBindViewHolder(MyViewHolder1 myViewHolder, int i) {
    switch (myViewHolder.getItemViewType()) {
        case TYPE_HEADER:

            // 获取cardview的布局属性,记住这里要是布局的最外层的控件的布局属性,如果是里层的会报cast错误
            StaggeredGridLayoutManager.LayoutParams clp = (StaggeredGridLayoutManager.LayoutParams) myViewHolder.cardview.getLayoutParams();
            // 最最关键一步,设置当前view占满列数,这样就可以占据两列实现头部了
            if(clp!=null)
                clp.setFullSpan(true);
            break;

        case TYPE_ITEM:
            ViewGroup.LayoutParams layoutParams=myViewHolder.cardview.getLayoutParams();
            layoutParams.height= (int) ((i%mDatas.size()+1)*20);
            myViewHolder.cardview.setLayoutParams(layoutParams);
            break;

        case TYPE_FOOT:
            // 获取cardview的布局属性,记住这里要是布局的最外层的控件的布局属性,如果是里层的会报cast错误
            StaggeredGridLayoutManager.LayoutParams clp1 = (StaggeredGridLayoutManager.LayoutParams) myViewHolder.cardview.getLayoutParams();
            // 最最关键一步,设置当前view占满列数,这样就可以占据两列实现头部了
            clp1.setFullSpan(true);

            break;
    }
}

@Override
public int getItemViewType(int position) {

    int type = TYPE_ITEM;
    if (headViewSize==1 && position == 0) {
        type = TYPE_HEADER;
    } else if (footViewSize==1 && position == getItemCount()-1) {
        //最后一个位置
        type = TYPE_FOOT;
    }
    return type;
}

@Override
public int getItemCount() {
    return mDatas.size()+headViewSize+footViewSize;
}
}

class MyViewHolder1 extends RecyclerView.ViewHolder{
public CardView cardview;
public MyViewHolder1(View itemView) {
    super(itemView);
    cardview = (CardView) itemView.findViewById(R.id.cv);
}
}

发现其实都很长不差不多太多 LinearLayoutManager没啥难点
GridLayoutManager 是要设置SpanSize每行的占位大小

StaggerLayoutManager 就是要获取StaggerLayoutManager的LayoutParams 的setFullSpan 方法来设置占位宽度

贴一贴布局代码

item

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/cv"
>
<ImageView
    android:id="@+id/iv_show"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/ic_launcher"
    />
</android.support.v7.widget.CardView >

top

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cv"
xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:cardCornerRadius="8dp"
app:cardElevation="5dp"
app:contentPadding="1dp"

>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="top"
    android:textSize="100dp" />
</android.support.v7.widget.CardView>

foot

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Foot"
    android:textSize="100dp" />
</android.support.v7.widget.CardView>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,380评论 25 707
  • Learn-Android 本收集来源于git上,原版本地址:https://github.com/Tim9Liu...
    仕明同学阅读 2,215评论 0 36
  • 1.我沿着职教中心外面的公路,一直往北走,路过了一个村庄。路的两旁有很多树。村子外面都是人。人群中有一个巨大的屏幕...
    死在田园阅读 212评论 0 0
  • 场景一:作为一个媳妇,跟公婆一起住,有一天,你在卧室看电视,吃着零食。婆婆进来,迅速的收拾了一下房间,将垃圾拿走,...
    要天天快乐阅读 271评论 0 1
  • 沟通的目的: 1、达成共识 2、采取行动
    Yel阅读 166评论 0 1