Android学习之RecyclerView快速添加头部布局

众所周知我们的ListView、GridView都可以增加头部布局;这样在遇到复杂的头部布局就不用增加视图类型了,不管是对于代码的可维护性还是整洁性;在Adapter中写又臭又长的代码,无论是自己看还是留给后来者都是痛苦的,而且你要是把代码都堆在getView中,oh no!我要分分钟切腹自尽…

RecyclerView增加头部布局传统方式


真的不是我懒,真的;传统方式我相信大家应该都会了,好吧我还是简单的说一下:(ps:这里我主要是增加了两种视图)
在RecyclerView.Adapter中复写getItemViewType方法

    /**
     * 重写该方法用以区分不同的视图
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return VIEW_HEADER;
        }
        return VIEW_ITEM;
    }

然后在onBindViewHolder中根据positon给不同的视图填充数据

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        if (getItemViewType(position) == VIEW_ITEM) {
            ...
            // 设置常规的数据数据
        } else if (getItemViewType(position) == VIEW_HEADER) {
            ...
            // 设置底部视图数据
        }...
    }

当然我们在创建ViewHolder的时候就要根据不同的视图来创建不同的ViewHolder,在onBindViewHolder方法返回的应该是ViewHolder而不是他们的子类,要用到相应的ViewHolder只要强制转换就好了,当然这也没什么好说的;以上方式可以应对列表中存在多种视图的情况,可以说是万精油;

RecyclerView快速添加顶部布局


到底是如何添加头部布局呢?好了我也不卖关子了;详情请看以下地址:

快速添加header https://github.com/blipinsk/RecyclerViewHeader

相信此时大家内心的OS是这样的“我去,早说是开源项目啊;”,哈哈,我要早说你们就不看了,开玩笑了啦我可没这么坏:);

看了RecyclerViewHeader的Usage相信大家也应该会用了,好了我们直接码代码了;
首先看一下项目依赖:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.0'
    compile 'com.android.support:cardview-v7:23.1.0'
    compile 'com.bartoszlipinski.recyclerviewheader:library:1.2.0'
    compile 'com.jakewharton:butterknife:7.0.1'
}

1.创建布局文件

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|top" />
        <com.bartoszlipinski.recyclerviewheader.RecyclerViewHeader
            android:id="@+id/header"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_gravity="center_horizontal|top"
            android:background="@android:color/holo_green_light">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="header" />
        com.bartoszlipinski.recyclerviewheader.RecyclerViewHeader>
    FrameLayout>
LinearLayout>

2.将RecyclerViewHeader和RecyclerView关联

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.header)
    RecyclerViewHeader mHeader;

    @Bind(R.id.recycler)
    RecyclerView mRecyclerView;

    MyAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        mAdapter = new MyAdapter(this,getList());
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter);
        // 将顶部视图与RecyclerView关联即可
        mHeader.attachTo(mRecyclerView, true);
    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0;i < 15;i++) {
            list.add("Item" + i);
        }
        return list;
    }
}

上面的视图我都是用ButterKnife自动注入的;

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ItemViewHolder> {

    private Context mContext;
    private LayoutInflater mInflater;
    private List mList;

    public MyAdapter(Context context,List list) {
        mContext = context;
        mList = list;
        mInflater = LayoutInflater.from(mContext);
    }

    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ItemViewHolder holder = new ItemViewHolder(mInflater.inflate(R.layout.view_item,parent,false));
        return holder;
    }

    @Override
    public void onBindViewHolder(ItemViewHolder holder, int position) {
        holder.mTextView.setText(getItem(position));
    }

    private String getItem(int position) {
        return mList.get(position);
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    class ItemViewHolder extends RecyclerView.ViewHolder {

        @Bind(R.id.textView)
        TextView mTextView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this,itemView);
        }
    }
}

3.运行效果图如下

如过到这里就结束的话肯定很多人会骂我,这不是把人家开源项目的例子重复了一遍吗,值得费这么多口舌吗;那么请耐心的你接着往下看了;

RecyclerView整合下拉刷新控件

下拉组件也是有很多的开源组件,这里我们就用Google自带的下拉组件好了;整合到视图中,下载布局改为如下方式:
activity_main.xml

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

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal|top" />

            <com.bartoszlipinski.recyclerviewheader.RecyclerViewHeader
                android:id="@+id/header"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_gravity="center_horizontal|top"
                android:background="@android:color/holo_green_light">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="header" />

            com.bartoszlipinski.recyclerviewheader.RecyclerViewHeader>

        FrameLayout>
    android.support.v4.widget.SwipeRefreshLayout>

LinearLayout>

MainActivity.java增加如下代码

@Bind(R.id.swipeRefreshLayout)
SwipeRefreshLayout mRefreshLayout;
...
mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
        mRefreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                mRefreshLayout.setRefreshing(false);
            }
        },2000);
    }
});

ScreenShot


由上图不难看出当我们加入下拉刷新组件时,在滑动到下面之后不能不能上滑到顶部了;原因肯定是header的触摸事件和刷新组件的冲突了;

修改源码

我们知道SwipeRefreshLayout可以设置enable属性使得该组件是否可用;有了这一点我们就可根据是否滑动到顶部来做判断,并设置SwipeRefreshLayout可用性;

可以庆幸的是这个开源代码只有一个类并且没有布局文件,这样的话我们直接拷贝这个java类到我们项目;

RecyclerViewHeader.java增加如下接口

    public interface OnScrollTopListener {
        void onTop(boolean isTop);
    }

    public OnScrollTopListener mOnScrollTopListener;

    public void setOnScrollTopListener(OnScrollTopListener onScrollTopListener) {
        mOnScrollTopListener = onScrollTopListener;
    }

我们在setupHeader方法中可以设置是否滚动到顶部的回调

@SuppressLint("NewApi")
    private void setupHeader(final RecyclerView recycler) {
        recycler.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                mCurrentScroll += dy;
                RecyclerViewHeader.this.setTranslationY(-mCurrentScroll);

                // 增加时候滚动的顶部回调
                if (mOnScrollTopListener != null) {
                    if (mCurrentScroll > 0) {
                        mOnScrollTopListener.onTop(false);
                    } else {
                        mOnScrollTopListener.onTop(true);
                    }
                }
            }
        });
        ...
    }

MainActivity.java中增加回调接口

    mHeader.setOnScrollTopListener(new RecyclerViewHeader.OnScrollTopListener() {
        @Override
        public void onTop(boolean isTop) {
            mRefreshLayout.setEnabled(isTop);
        }
    });

记得把activity_main.xml中的RecyclerViewHeader替换成我们本地的类路经;图我就不截了。。。

总结

为什么会大费周章介绍一个顶部布局,可能也是因为自己贱吧,在项目中想尝试新的东西;可是纯列表布局真的是很少,不是要在头部加个图片就是加个按钮;这样就会导致你要在Adapter中增加一种视图类型,但是Adapter中为一个顶部增加布局是很繁琐的,而且当顶部很复杂的时候;于是就看到了Github上有这种方案,有简单又方便何不拿来用呢;

注意:该项目中还是存在一些bug就比如我文中提到的那个,需要自行修改;如果引入项目中测试没有问题方可用,如果有能力可以自行修改源码(毕竟也就一个类吗,也是一个学习的机会);如果实在遇到了问题,可以看看Github中的issuses,还是解决不了换用ListView或者使用传统方式;

最后

RecyclerView真的要替代ListView了吗?我会在下一篇中文章中说说这段时间使用的感受;

你可能感兴趣的:(Android,android,布局)