首页 > 其他 > 详细

RecyclerView综合解析

时间:2016-04-29 15:16:33      阅读:179      评论:0      收藏:0      [点我收藏+]

RecyclerView

什么是RecyclerView?

RecyclerView其实就是一个在5.0推出的控件,可以用它来代替ListView和GridView,从这一点也能看出来它的特性和ListView以及GridView类似,注意我说的是整体上类似,既然是更高的版本推出的,岂能再和再和低版本的小崽子们一个层次,所以它加入了很多新的特征,下面会讲到。

为什么叫RecyclerView?

虽然在计算机界,起名字一直都比较个性,比较不符合常理,通常情况下试图通过名字来了解一件事物的人都会走火入魔,想当年,我就想知道android为啥叫android,是不是什么缩写,但是后来确实让朕很失望,类似的还有apple(这里指手机),oracle(甲骨文)通过这些名字来了解一些事物真是相当困难,但是RecyclerView和他的功能还是有一些联系的:

  1. RecyclerView不关心Item是否显示在正确的位置,以及如何显示。
  2. RecyclerView不关心Item之间如何间隔。
  3. 不关注Item增加与删除的动画效果。
  4. 它只关注如何回收和复用View(这就是叫RecycleView的原因)。

嗯?什么都不关心,那还玩个毛线啊?
这位看官说的好,RecyclerView既然敢这么玩,当然是有手段的:

  1. 不关心Item是否显示在正确的位置,以及如何显示,此时我们用LayoutManager来解决。
  2. 不关心Item之间如何间隔,此时我们用ItemDecoration来解决。
  3. 不关心Item的增加与删除的动画效果,此时用ItemAnimator来解决。

看到了吧,真正牛逼的人是不需要什么都管的,只要有人就行。

这位看官又问啦,RecyclerView都有啥人(相关类)啊?看官且看:

  • Adapter
  • ViewHolder
  • LayoutManager
  • ItemDecoration
  • ItemAnimator

O啦,主公以及大将都悉数登场了,看官可能又要问了,这阵容能干点啥大事呢? 嗯,问的好,以下就是此阵容能干的事:

  1. Just like ListView(实现listview的效果)
  2. Just like GridView(实现GridView的效果)
  3. 实现横向的ListView效果
  4. 实现横向的GridView效果
  5. 实现瀑布流(此处可以通过名字来理解其效果)
  6. 定制Item增加和删除动画

都是字啊,是骡子是马拉出来溜溜,来图让我看看!好,看官既然这么急切,那就来一波:

实现listview的效果

技术分享

实现垂直GridView的效果

技术分享

实现横向的GridView效果
技术分享

瀑布流:

技术分享

动画效果(可以自己设置各种动画)

技术分享

好,准备工作完成,开始编写:

实现Recyclerview

首先:导入android-support-v7-recyclerview.jar包,如果是android studio 直接加入依赖即可。

设置主布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >
    <android.support.v7.widget.RecyclerView
        android:id="@+id/idrecyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!" />
</RelativeLayout>

item布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark"
   >
    <TextView
        android:id="@+id/item_recyclerview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

MainActivity代码:

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private List<String> list;
    private SimpleAdap adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        iniDatas();

        iniView();
        adapter = new SimpleAdap(this,list);
        recyclerView.setAdapter(adapter);
        //设置以listview形式显示
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
        recyclerView.setLayoutManager(layoutManager);
    }

    private void iniView() {
        recyclerView = (RecyclerView) findViewById(R.id.idrecyclerview);
    }

    private void iniDatas() {
        list = new ArrayList<>();
        Random ran = new Random(50);
        for(int i=0;i<50;i++){
            list.add(String.valueOf(ran.nextInt())+i);
        }
    }
}
class SimpleAdap extends RecyclerView.Adapter<MyViewHolder>{

    private LayoutInflater layoutInflater;
    private List<String> mData;
    private Context context;
    public SimpleAdap(Context context, List<String> list) {
        this.context = context;
        mData = list;
        layoutInflater = LayoutInflater.from(context);
    }

    //google将对viewholder的操作分成了两步,创建和绑定,体现了google对viewholder的强制性
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = layoutInflater.inflate(R.layout.item_recyclerview,parent,false);
        MyViewHolder myViewHolder = new MyViewHolder(view);
        return myViewHolder;
    }

    //绑定数据
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.text.setText(mData.get(position));
    }

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

class MyViewHolder extends RecyclerView.ViewHolder {
 public TextView text;
    public MyViewHolder(View itemView) {
        super(itemView);
        text = (TextView) itemView.findViewById(R.id.item_recyclerview);
    }
}

此时的item之间是没有分割线的
如图:

技术分享

这怎么能行呢?跟块黑板似的,listview得有分割线啊!
看官且看下面,待我添加分割线!

添加分割线

其实对于recyclerView来说,添加分割线很简单,可以交给它的小弟ItemDecoration来实现:

 //设置listview之间的分割线
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST);
        recyclerView.addItemDecoration(dividerItemDecoration);//参数是抽象类itemDecoration的实现类,因为没有现成的,所以从github download一个

需要注意的是,recyclerView.addItemDecoration(dividerItemDecoration);中传入的参数系统并没有为我们提供,我在此是在github上down的一个类,链接地址

现在有了分割线,如图:

技术分享

利用github上的源码自定义分割条

看官心中是否有疑问,这个白色的分割线是设置的颜色?还是图片?从哪设置的?
这就需要看刚才从github上下载的那个源码了

在源码中,有这么一句代码:

final TypedArray a = context.obtainStyledAttributes(ATTRS);

通过顺藤摸瓜,我们就可以知道,白色分割线就是从style中得到的,哼哼,知道了这些那就好办了,我们可以自定义我们的分割条了。

只需要在styles.xml中添加这样的一句代码:

<item name="android:listDivider">@drawable/ic_launcher</item>

此时我用系统提供的一张图片来作为分割线,如图所示:

技术分享

什么?没有看到分割线? android图标那个就是分割线(确实有点大)

在此只是实例,在正式使用的时候,我们完全可以自定义一个drawale,然后进行设置。

实现GridView

在实现之前先说一点,当我们使用recyclerview的时候,要把它作为listview和gridview的综合体,不要总想着以前的listview和gridview是两个不同的控件,这是一个思想上的转变(思想是最重要的)。

竖直gridview

//第二个参数为gridview的列数
recyclerView.setLayoutManager(new GridLayoutManager(this,4));

横向gridview

recyclerView.setLayoutManager(new StaggeredGridLayoutManager(5,StaggeredGridLayoutManager.HORIZONTAL));

注意:在使用水平的gridview的是有,itemview的宽不能为match_parent,并且上面分割线的设置在此也不适用了。

瀑布流

瀑布流,其实就是item的宽或者高不一样,造成参差不齐的效果而已!

设置瀑布管理器:

        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));

在适配器中初始化一个数据集合:

mHeight = new ArrayList<>();
        for(int i=0;i<mData.size();i++){
            mHeight.add((int) (100+Math.random()*300));
        }

在onBindViewHolder中设置item高度:

public void onBindViewHolder(seViewHolder holder, int position) {
        holder.text.setText(mData.get(position));
        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
        layoutParams.height = mHeight.get(position);
        holder.itemView.setLayoutParams(layoutParams);
    }

增加删除动画

设置动画:

recyclerView.setItemAnimator(new DefaultItemAnimator());

在适配器中添加两个方法:

public void add(int position){
        mData.add(position,"Insert data");
        notifyItemInserted(position);//此处要注意,和listview不一样
    }

    public void delete(int position){
        mData.remove(position);
        notifyItemRemoved(position);
    }

在onOptionsItemSelected中调用方法:

public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.listview:
                recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
                break;
            case R.id.heng_listview:
                break;
            case R.id.gridview:
                recyclerView.setLayoutManager(new GridLayoutManager(this,4));
                //recyclerView.addItemDecoration(dividerItemDecoration);
                break;
            case R.id.heng_grid:
                recyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.HORIZONTAL));
                break;
            case R.id.pubu:
                Intent intent = new Intent(this,PubuActivity.class);
                startActivity(intent);
                break;
            case R.id.delete:
                adapter.delete(1);
                break;
            case R.id.add:
                adapter.add(1);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

添加监听

说到recyclerview的监听,我要告诉看官一个悲伤的故事—-recyclerview的监听需要自己实现

实现监听的方式有很多,在此,利用在适配器中设置接口回调的方法!

在适配器中定义接口:

public interface  OnItemClickListener{
        void onItemClick(View view,int position);
        void onItemLongClick(View view,int position);
    }

对外提供方法:

private OnItemClickListener onItemClickListener;
    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener = onItemClickListener;
    }

在中定义监听:

public void onBindViewHolder(MyViewHolder holder, final int position) {
        holder.text.setText(mData.get(position));
//        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
//        layoutParams.height = mHeight.get(position);
//        holder.itemView.setLayoutParams(layoutParams);
        if(onItemClickListener!=null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onItemClickListener.onItemClick(v, position);
                }
            });
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    onItemClickListener.onItemLongClick(v, position);
                    return false;
                }
            });
        }
    }

使用回调方法设置监听:

adapter.setOnItemClickListener(new SimpleAdap.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, "item"+position, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(MainActivity.this, "long"+position, Toast.LENGTH_SHORT).show();
            }
        });

注意:如果我们此时利用上面介绍的添加删除item的方法,添加了或者删除了item,这是我们点击item的时候,会发现position会不正常,具体表现在当我们添加多个item的时候,会发现所添加的每个item点击的时候都是同一个position。

解决方法:

public void onBindViewHolder(final MyViewHolder holder, final int position) {
        holder.text.setText(mData.get(position));
        if(onItemClickListener!=null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int layoutPosition = holder.getLayoutPosition();//用此方法得到全局position,传入点击事件中
                    onItemClickListener.onItemClick(v, layoutPosition);
                }
            });
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int layoutPosition = holder.getLayoutPosition();
                    onItemClickListener.onItemLongClick(v, layoutPosition);
                    return false;
                }
            });
        }
    }

OK,散会!

相关知识点,是本人对慕课网相关课程的总结,也是作为自己的学习记录

RecyclerView综合解析

原文:http://blog.csdn.net/u013240038/article/details/51264428

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!