美文网首页android使用Android开发程序员
RecyclerView使用完全指南(一)

RecyclerView使用完全指南(一)

作者: 侯蛋蛋_ | 来源:发表于2017-09-18 08:51 被阅读0次

概述

RecyclerView(一)使用完全指南
RecyclerView(二)之万能分割线
RecyclerView之瀑布流(三)

官方介绍,RecyclerView用于在有限的窗口展现大量的数据,其实早已经有了类似的控件,如ListView、GridView,那么相比它们,RecyclerView有什么样优势呢?
RecyclerView标准化了ViewHolder,而且异常的灵活,可以轻松实现ListView实现不了的样式和功能,通过布局管理器LayoutManager可控制Item的布局方式,通过设置Item操作动画自定义Item添加和删除的动画,通过设置Item之间的间隔样式,自定义间隔。

  • 设置布局管理器以控制Item的布局方式,横向、竖向以及瀑布流方式。
  • 可设置Item操作的动画(删除或者添加等)
  • 可设置Item的间隔样式(可绘制)
  • 但是关于Item的点击和长按事件,需要用户自己去实现。

在使用RecyclerView时候,必须指定一个适配器Adapter和一个布局管理器LayoutManager。适配器继承RecyclerView.Adapter类,具体实现类似ListView的适配器,取决于数据信息以及展示的UI。布局管理器用于确定RecyclerView中Item的展示方式以及决定何时复用已经不可见的Item,避免重复创建以及执行高成本的findViewById()方法。

来看一下用法。


mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// 设置布局管理器
mRecyclerView.setLayoutManager(mLayoutManager);
// 设置adapter
mRecyclerView.setAdapter(mAdapter);
// 设置Item添加和移除的动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// 设置Item之间间隔样式(分割线)

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

可以看见RecyclerView相比ListView会多出许多操作,这也是RecyclerView灵活的地方,它将许多动能暴露出来,用户可以选择性的自定义属性以满足需求。

RecyclerView提供了三种布局管理器:

  • LinerLayoutManager 以垂直或者水平列表方式展示Item
  • GridLayoutManager 以网格方式展示Item
  • StaggeredGridLayoutManager 以瀑布流方式展示Item

基本使用

Activity代码

  public class HomeActivity extends ActionBarActivity
{

    private RecyclerView mRecyclerView;
    private List<String> mDatas;
    private HomeAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_recyclerview);

        initData();
        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter = new HomeAdapter());

    }

    protected void initData()
    {
        mDatas = new ArrayList<String>();
        for (int i = 'A'; i < 'z'; i++)
        {
            mDatas.add("" + (char) i);
        }
    }

    class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
    {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    HomeActivity.this).inflate(R.layout.item_home, parent,
                    false));
            return holder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position)
        {
            holder.tv.setText(mDatas.get(position));
        }

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

        class MyViewHolder extends ViewHolder
        {

            TextView tv;

            public MyViewHolder(View view)
            {
                super(view);
                tv = (TextView) view.findViewById(R.id.id_num);
            }
        }
    }

}

Activity布局文件activity_rv.xml

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

Item的布局文件item_home.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="@dimen/md_common_view_height">
    <TextView
        android:id="@+id/item_tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        tools:text="item"/>
</LinearLayout>
  • 运行结果如下:

RecyclerView-无间隔.jpg

可以看见展示效果和ListView基本上无差别,但是Item之间并没有分割线,在xml去找divider属性的时候,发现RecyclerView没有divider属性,当然也可以在Item布局中加上分割线,但是这样做并不是很优雅。前文说过,RecyclerView可是支持自定义间隔样式的。通过mRecyclerView.addItemDecoration()来设置我们定义好的间隔样式。

默认分割线

水平分割线

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), LinerLayoutManager.HORIZONTAL));

垂直分割线

        mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL, false));

mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), LinerLayoutManager.HORIZONTAL));

这里的HORIZONTAL 是设置垂直分割线 而DividerItemDecoration.VERTICAL是设置水平分割线

注:如果布局管理器中的LinearLayoutManager.HORIZONTAL和分割线样式LinearLayoutManager.VERTICAL则不会显示

动画

前面说过,RecyclerView可以设置列表中Item删除和添加的动画,在v7包中给我们提供了一种默认的Item删除和添加的动画,如果没有特殊的需求,默认使用这个动画即可。

// 设置Item添加和移除的动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());

下面就添加一下删除和添加Item的动作。在Adapter里面添加方法。

public void addNewItem() {
    if(mData == null) {
        mData = new ArrayList<>();
    }
    mData.add(0, "new Item");
    notifyItemInserted(0);
}

public void deleteItem() {
    if(mData == null || mData.isEmpty()) {
        return;
    }
    mData.remove(0);
    notifyItemRemoved(0);
}

添加事件的处理。

public void onClick(View v) {
    int id = v.getId();
    if(id == R.id.rv_add_item_btn) {
        mAdapter.addNewItem();
        // 由于Adapter内部是直接在首个Item位置做增加操作,增加完毕后列表移动到首个Item位置
        mLayoutManager.scrollToPosition(0);
    } else if(id == R.id.rv_del_item_btn){
        mAdapter.deleteItem();
        // 由于Adapter内部是直接在首个Item位置做删除操作,删除完毕后列表移动到首个Item位置
        mLayoutManager.scrollToPosition(0);
    }
}

准备工作完毕后,来看一下运行的效果。

RecyclerView-动画.gif

点击事件

RecyclerView并没有像ListView一样暴露出Item点击事件或者长按事件处理的api,也就是说使用RecyclerView时候,需要我们自己来实现Item的点击和长按等事件的处理。实现方法有很多,可以监听RecyclerView的Touch事件然后判断手势做相应的处理,也可以通过在绑定ViewHolder的时候设置监听,然后通过Apater回调出去,我们选择第二种方法,更加直观和简单。

先看一下效果

GIF.gif

原理

为RecyclerView的每个子item设置setOnClickListener,然后在onClick中再调用一次对外封装的接口,将这个事件传递给外面的调用者。而“为RecyclerView的每个子item设置setOnClickListener”在Adapter中设置。其实直接在onClick中也能完全处理item的点击事件,但是这样会破坏代码的逻辑。

步骤

1、在MyAdapter中定义接口
public interface OnItemClickListener{
     void onItemClick(int position);
}
2、声明这个接口变量
private OnItemClickListener mItemClickListener;
3、在onCreateViewHolder()中为每个item添加点击事件
@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = View.inflate(mContext, R.layout.item_linear, null);
        RecyclerView.ViewHolder holder = new LinearViewholder(view);
      //这两句也可以这样写,效果都是一样的
      //View view =LayoutInflater.from(parent.getContext()).inflate(R.layout.item_home, parent, false);
    //RecyclerView.ViewHolder holder =new ViewHolder
        view.setOnClickListener(this);
        return holder;
    }
@Override
   public void onClick(View v) {
     if (mItemClickListener!=null){
         mItemClickListener.onItemClick((Integer) v.getTag());
        }
    }
4、注意上面调用接口的onItemClick()中的v.getTag()方法,这需要在onBindViewHolder()方法中设置和item相关的数据
 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        LinearViewholder viewholder = (LinearViewholder) holder;
        viewholder.mTextView.setText(mList.get(position));
        viewholder.itemView.setTag(position);
    }
5、提供set方法
public void setItemClickListener(OnItemClickListener itemClickListener) {
        mItemClickListener = itemClickListener;
    }
6、在MainActivity中
MyRecyclerViewAdapter adapter = new MyRecyalerViewAdapter();
    adapter.setItemClickListener(this);
 @Override
    public void onItemClick(int position) {
        Toast.makeText(this, ""+position, Toast.LENGTH_SHORT).show();
    }

上面这是一种算是比较负责的一种了吧,下面介绍一种简单的,当然上面的也要自己弄明白的

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{

//...
    public interface OnItemClickLitener
    {
        void onItemClick(View view, int position);
        void onItemLongClick(View view , int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.tv.setText(mDatas.get(position));

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    return false;
                }
            });
        }
    }
//...
}

根据王三的猫阿德加以改编

相关文章

网友评论

    本文标题:RecyclerView使用完全指南(一)

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