Android 开发之 RecyclerView相关知识

来源:互联网 发布:哪里买高仿手表知乎 编辑:程序博客网 时间:2024/06/05 08:52

简介

RecyclerView已经出来相当长一段时间了,现在目前开发过程中大部分的列表数据使用的RecyclerView。为什么广泛使用此控件呢,相比ListView的区别在哪里?因为这个控件自身有优化处理,你只需要设置布局填入数据即可,这点比Listview好很多。在布局管理方面,有三种,比listView强太多了。但是也有部分仍旧在使用listview,毕竟listview优化处理好了,简单的数据也是很好的处理的。
RecyclerView涉及到的知识:
1.三种布局管理器:LinearLayoutManager,GridLayoutManager,StaggeredGridLayoutManager;
2.设置item之间的分割线 ItemDecoration;
3.item的添加和删除动画ItemAnimator。

1. 基本用法和三种布局管理器的使用和效果

recyclerView = (RecyclerView) findViewById(R.id.rc_photo);recyclerView.setLayoutManager(new GridLayoutManager(this,4));//设置布局管理器recyclerView.setItemAnimator(new DefaultItemAnimator());//设置item动画效果recyclerView.addItemDecoration(new DividerGridItemDecoration(this));//设置item的分割线recyclerView.setAdapter(new FirstAdapter());//设置recyclerview的适配器。

适配器的代码;
    public class FirstAdapter extends RecyclerView.Adapter{        @Override        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.rcv_item_layout, parent, false);            MyViewHolder holder=new MyViewHolder(view);            return holder;        }        @Override        public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {            if(holder instanceof MyViewHolder)            {                MyViewHolder mholder= (MyViewHolder) holder;                mholder.tv.setText("第 "+list.get(position)+" item");                mholder.tv.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View view) {                        Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show();                    }                });            }        }        @Override        public int getItemCount() {            return list.size();        }    }    public class MyViewHolder extends RecyclerView.ViewHolder    {        public TextView tv;        public MyViewHolder(View itemView) {            super(itemView);            tv = (TextView) itemView.findViewById(R.id.tv_itemcount);        }    }



1).LinearLayoutManager的使用,效果和listview是一样的,只需要执行下面的代码就可以实现

recyclerView.setLayoutManager(new LinearLayoutManager(this));

2).GridLayoutManager的使用,效果和GridView效果类似。
recyclerView.setLayoutManager(new GridLayoutManager(this,4));//第二个参数是列数
3).StaggeredGridLayoutManager的使用

recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));//第一个是列数,第二个是方向

2. 各个布局管理器的分割线的适配
1).线性布局管理器LinearLayoutManager。系统的分割线如下
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);qRecycleView.addItemDecoration(dividerItemDecoration);




这是系统的分割线,但是如果不满意,想自己定义的话也是可以实现的。
DividerItemDecoration该实现类可以看到通过读取系统主题中的 Android.R.attr.listDivider作为Item间的分割线
先定义一个shape
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <gradient android:startColor="#F00"        android:endColor="#0F0"        android:centerColor="#00f"        android:type="linear">    </gradient>    <size android:height="4px">    </size></shape>
在把这个shape设置到主题中
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">                <item name="android:listDivider">@drawable/shape_itemdecoration</item>    </style>


2).但是自定义的这种不能使用到GridLayoutManager上,为了适配,我们必须重写android的DividerItemDecoration这个类,动态的区划item的边界
package com.zwg.xjkb.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.LayoutManager;import android.support.v7.widget.RecyclerView.State;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.View;public class DividerGridItemDecoration extends RecyclerView.ItemDecoration{    private static final int[] ATTRS = new int[] { android.R.attr.listDivider };    private Drawable mDivider;    public DividerGridItemDecoration(Context context)    {        final TypedArray a = context.obtainStyledAttributes(ATTRS);        mDivider = a.getDrawable(0);        a.recycle();    }    @Override    public void onDraw(Canvas c, RecyclerView parent, State state)    {        drawHorizontal(c, parent);        drawVertical(c, parent);    }    private int getSpanCount(RecyclerView parent)    {        // 列数        int spanCount = -1;        LayoutManager layoutManager = parent.getLayoutManager();        if (layoutManager instanceof GridLayoutManager)        {            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();        } else if (layoutManager instanceof StaggeredGridLayoutManager)        {            spanCount = ((StaggeredGridLayoutManager) layoutManager)                    .getSpanCount();        }        return spanCount;    }    public void drawHorizontal(Canvas c, RecyclerView parent)    {        int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++)        {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int left = child.getLeft() - params.leftMargin;            final int right = child.getRight() + params.rightMargin                    + mDivider.getIntrinsicWidth();            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    public void drawVertical(Canvas c, RecyclerView parent)    {        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++)        {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int top = child.getTop() - params.topMargin;            final int bottom = child.getBottom() + params.bottomMargin;            final int left = child.getRight() + params.rightMargin;            final int right = left + mDivider.getIntrinsicWidth();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    private boolean isLastColum(RecyclerView parent, int pos, int spanCount,                                int childCount)    {        LayoutManager layoutManager = parent.getLayoutManager();        if (layoutManager instanceof GridLayoutManager)        {            if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边            {                return true;            }        } else if (layoutManager instanceof StaggeredGridLayoutManager)        {            int orientation = ((StaggeredGridLayoutManager) layoutManager)                    .getOrientation();            if (orientation == StaggeredGridLayoutManager.VERTICAL)            {                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边                {                    return true;                }            } else            {                childCount = childCount - childCount % spanCount;                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边                    return true;            }        }        return false;    }    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,                              int childCount)    {        LayoutManager layoutManager = parent.getLayoutManager();        if (layoutManager instanceof GridLayoutManager)        {            childCount = childCount - childCount % spanCount;            if (pos >= childCount)// 如果是最后一行,则不需要绘制底部                return true;        } else if (layoutManager instanceof StaggeredGridLayoutManager)        {            int orientation = ((StaggeredGridLayoutManager) layoutManager)                    .getOrientation();            // StaggeredGridLayoutManager 且纵向滚动            if (orientation == StaggeredGridLayoutManager.VERTICAL)            {                childCount = childCount - childCount % spanCount;                // 如果是最后一行,则不需要绘制底部                if (pos >= childCount)                    return true;            } else            // StaggeredGridLayoutManager 且横向滚动            {                // 如果是最后一行,则不需要绘制底部                if ((pos + 1) % spanCount == 0)                {                    return true;                }            }        }        return false;    }    @Override    public void getItemOffsets(Rect outRect, int itemPosition,                               RecyclerView parent)    {        int spanCount = getSpanCount(parent);        int childCount = parent.getAdapter().getItemCount();        if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部        {            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边        {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());        } else        {            outRect.set(0, 0, mDivider.getIntrinsicWidth(),                    mDivider.getIntrinsicHeight());        }    }}
在这里要给上面写的shape中size节点添加一个width属性,不然无法显示,android:width="4dp"。


3.item的动画效果。
ItemAnimator也是一个抽象类,好在系统为我们提供了一种默认的实现类,期待系统多添加些默认的实现。
// 设置item动画,这个系统的动画效果。mRecyclerView.setItemAnimator(new DefaultItemAnimator());

在adapter编写这两个方法
public void addData(int position) {        mDatas.add(position, "Insert One");        notifyItemInserted(position);    }    public void removeData(int position) {            mDatas.remove(position);        notifyItemRemoved(position);    }

在Activity中添加两个menu
@Override    public boolean onCreateOptionsMenu(Menu menu)    {        getMenuInflater().inflate(R.menu.main, menu);        return super.onCreateOptionsMenu(menu);    }    @Override    public boolean onOptionsItemSelected(MenuItem item)    {        switch (item.getItemId())        {        case R.id.id_action_add:            mAdapter.addData(1);            break;        case R.id.id_action_delete:            mAdapter.removeData(1);            break;        }        return true;    }

系统动画效果还可以,要想更多了动画效果,自己可以搜索。
到此这个控件的基本使用已经完全可以搞定了。

原创粉丝点击