Android—RecyclerView带你飞

来源:互联网 发布:淘宝网懒人桌 编辑:程序博客网 时间:2024/06/08 16:45

1、RecyclerView是什么?

  根据Googl给出的说明:“能够在有限的窗口中展示大数据集合的灵活视图”
  RecyclerView看上去和我们一直用的ListVIew可以说很是一样,但是我们为什么还要用RecyclerView呢?
  首先我们先来看一个场景,由于尺寸限制,用户的设备不能以此性展示所有条目,用户需要上下滚动查看会更多的的条目。滚出可见区域的条目将被回收,并在下一条目可见的时候被复用。
  在这个场景可以知道,RecyclertView的缓存可以更大的减少内存的开销和CPU的计算,这意味着我们不用每次都创建新的条目,这样就大大的减少了内存开销和CPU的计算。,有效的降低屏幕的卡顿,保证滑动的顺滑。
  说了半天你们会说还是没有说明白和LIstView的区别,毕竟我们用ListView很长一段时间了,其实在应用RecyclerView的时候,RecyclerView只管回收和复用View,其他的我们自己去设置。可以根据开发者的需要去设置任何样式的的动画和布局View,可以很轻松的实现LsitView和GirdView,瀑布流的效果。

2、引入RecyclerView

  我们在应用RecyclerView的时候,需要添加依赖。
compile 'com.android.support:appcompat-v7:25.3.1'compile 'com.android.support:recyclerview-v7:25.3.1'
在添加依赖的时候这两个依赖包的版本号要统一,否则会报错。

3、在布局文件中应用RecyclerView

  
<android.support.v7.widget.RecyclerView    android:id="@+id/recycler_view"    android:layout_width="match_parent"    android:layout_height="match_parent" />


4、使用RecyclerView

我们先来了解一下RecyclerView中几个重要的类,都是内部类Class功能Adapter处理数据集合并负责绑定数据ViewHolder持有所有的用于绑定数据或者需要操作的ViewLayoutManager负责摆放视图等相关操作ItemDecoration负责绘制Item附近的分割线ItemAnimator为Item的一般操作添加动画效果

4.1RecyclerView.ViewHolder

这里的ViewHolder和ListVIew里面的ViewHolder差不多是一样的,但是在ListView中,并没有强制我们使用ViewHolder,但是在RecyclerView中,Google强制我们必须使用ViewHolder这种模式。(不了解ViewHolder可以去查一下,网上有很多说明,面试重点)
在RecycleView中的ViewHolder子类可以通过访问公共成员itemView来访问ViewHolder的根视图,所以不需要再ViewHolder子类中存储。
public static class MyViewHolder extends RecyclerView.ViewHolder {    TextView tv;    public MyViewHolder(View itemView) {        super(itemView);        tv = (TextView) itemView.findViewById(R.id.tv);    }}

4.2、Adapter

adapter有两个功能。一.根据不同Viewtype创建与之相应的Item-Layout,二.访问数据集合并将数据绑定到正确的View上。在实现这两个方面的时候,需要我们重写三个方法:
。public VH onCreateViewHolder(ViewGroup parent,int ViewType)创建Item视图,并返回相应的ViewHolder
。public void onBindViewHolder(VH holder,int position)绑定数据到正确的Item视图上
。public int getItemCount()返回该Adapter所持有的item数量
@Overridepublic MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)            .inflate(R.layout.item_recycler_view, parent, false));    return holder;}@Overridepublic void onBindViewHolder(MyViewHolder holder, final int position) {    holder.tv.setText(mDatas.get(position));}@Overridepublic int getItemCount() {    return mDatas.size();}

4.3、RecyclerView.LayoutManager

LayoutManager的职责是摆放Item的位置,并且负责决定何时回收和重用item。他有一个默认的实现:LinearLayoutManager,他可以用于垂直和水平列表。RecycleVIew.LayoutManager是一个抽象类,RecycleView提供了三个实现类:
1、LinearlayoutManager现行管理器,支持横向,纵向。
2、GridLayoutManager网格布局管理器
3、StaggeredGridLayoutManager瀑布流式布局管理器

     4.3.1LinearlayoutManager

LinearlayoutManager是LayoutManager的默认实现。可以使用这个类来创建垂直或水平列表

设置纵向布局
LinearLayoutManager layoutManager= new LinearLayoutManager(this);layoutManager.setOrientation(LinearLayoutManager.VERTICAL);recyclerView.setLayoutManager(layoutManager);
设置横向布局
LinearLayoutManager layoutManager= new LinearLayoutManager(this);layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);recyclerView.setLayoutManager(layoutManager);
在LinearLayoutManager中还有一些很实用的API:
。findFirstVisibleItemPosition()返回当前第一个可见的Item的position
。findLastVisibleItemPosition()返回当前最后一个可见的Item的position
。findFirstCompletelyVisibleItemPosition()返回当前的第一个完全可见的Item的position
。findLastCompletelyVisibleItemPosition()返回当前最后一个完全可见Item的position
剩下的两个RecycleView的实现类就不多说了,大家可以查看官方文档,很简单。

4.4、RecyclerView.ItemDecoration

设置:
// 给纵向显示RecyclerView设置分割线recyclerView.addItemDecoration(new DividerItemDecoration(activity, DividerItemDecoration.VERTICAL));// 给横向显示RecyclerView设置分割线recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecoration.HORIZONTAL));
当然,我们也可以对RecyclerView设置多个ItemDecoration,列表展示的时候会遍历所有的ItemDecoration并调用里面的绘制方法,对Item进行装饰。
RecyclerView.ItemDecoration也是一个抽象类,重写他的三个方法来实现Item之间的偏移量或者装饰效果:
。public void onDraw(Canvas c,RecyclerView parent)装饰的绘制在Item条目绘制之前调用,所以这有可能被Item的内容所遮挡
。public void onDrawOver(Canvas c,RecyclerView  parent)装饰的绘制在Item条目绘制之后调用,因此装饰奖浮于Item之上
。public void getItemOffsets(Rect outRect,int itemPositon,RecyclerView parent)和padding或者margin类似,LayoutManager在测量阶段会调用这个方法,计算出每一个Item的正确尺寸并设置偏移量。

4.5、RecyclerView.ItemAnimator

ItemAnimator能够帮助Item实现独立的动画。我们可以通过以下代码为Item增加动画效果:
recyclerView.setItemAnimator(new DefaultItemAnimator());
在之前我们开发过程中,表中的集合发生改变的时候,我们通过调用.notifyDataSetChanged()来刷新列表,这样做会触发列表重绘,所以并不会出现任何动画效果,因此需要调用一些以notifyItem*()最为作为前缀的特殊方法。
。public final void notifyItemInserted(int  position)向指定位置插入Item
。public final void notifyItemRemoved(int position)移除指定位置的Item
。public final void notifyItemChanged(int position)更新指定位置Item
例:
btnAdd.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        adapter.addData(1);    }});btnRemove.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        adapter.removeData(2);    }});
在适配器中添加两个方法:
public void addData(int position) {    mDatas.add(position, "新添加的");    mHeights.add( (int) (100 + Math.random() * 300));    notifyItemInserted(position);}public void removeData(int position) {    mDatas.remove(position);    notifyItemRemoved(position);}
下面给大家上一下全部代码:
public class MainActivity extends Activity {    private Activity activity;    private Button btnAdd,btnRemove;    private RecyclerView recyclerView;    private RecyclerAdapter adapter;    private List<String> mDatas = new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        activity = this;        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);        btnAdd = (Button) findViewById(R.id.btn_add);        btnRemove = (Button) findViewById(R.id.btn_remove);        initDatas();        adapter = new RecyclerAdapter(activity,mDatas);        // 设置RecyclerView布局方式为纵向布局//        LinearLayoutManager layoutManager= new LinearLayoutManager(this);//        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//        recyclerView.setLayoutManager(layoutManager);        // 设置RecyclerView布局方式为横向布局//        LinearLayoutManager layoutManager= new LinearLayoutManager(this);//        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//        recyclerView.setLayoutManager(layoutManager);        // 设置纵向的4列的表格布局//        GridLayoutManager layoutManager = new GridLayoutManager(this,4,GridLayoutManager.VERTICAL,false);//        recyclerView.setLayoutManager(layoutManager);//        recyclerView.addItemDecoration(new DividerGridItemDecoration(activity));l        // 设置横向的3行的表格布局//        GridLayoutManager layoutManager = new GridLayoutManager(this,3,GridLayoutManager.HORIZONTAL,false);//        recyclerView.setLayoutManager(layoutManager);        // 给纵向显示RecyclerView设置分割线//        recyclerView.addItemDecoration(new DividerItemDecoration(activity, DividerItemDecoration.VERTICAL));        // 给横向显示RecyclerView设置分割线//        recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecoration.HORIZONTAL));        // 设置纵向的瀑布流布局        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);        recyclerView.setLayoutManager(layoutManager);        // 给RecyclerView设置默认动画效果        recyclerView.setItemAnimator(new DefaultItemAnimator());        adapter.setLitener(new RecyclerAdapter.OnItemClickLitener() {            @Override            public void onItemClick(View view, int position) {                Toast.makeText(activity,"第"+(position+1)+"项被点击了",Toast.LENGTH_SHORT).show();            }            @Override            public void onItemLongClick(View view, int position) {                Toast.makeText(activity,"第"+(position+1)+"项被长按了",Toast.LENGTH_SHORT).show();            }        });        recyclerView.setAdapter(adapter);        btnAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                adapter.addData(1);            }        });        btnRemove.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                adapter.removeData(2);            }        });    }    private void initDatas(){        for (int i = 0;i<50;i++){            mDatas.add(String.valueOf(i+1));        }    }}
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {    private Context context;    private List<String> mDatas;    private List<Integer> mHeights;    public RecyclerAdapter(Context context, List<String> mDatas) {        this.context = context;        this.mDatas = mDatas;        mHeights = new ArrayList<Integer>();        for (int i = 0; i < mDatas.size(); i++) {            mHeights.add((int) (100 + Math.random() * 300));        }    }    @Override    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)                .inflate(R.layout.item_recycler_view, parent, false));        return holder;    }    @Override    public void onBindViewHolder(MyViewHolder holder, final int position) {        ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();        lp.height = mHeights.get(position);        holder.tv.setLayoutParams(lp);        holder.tv.setText(mDatas.get(position));        // 如果设置了回调,则响应点击事件        holder.itemView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (litener != null) {                    litener.onItemClick(v, position);                }            }        });        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                if (litener != null) {                    litener.onItemLongClick(v, position);                }                return false;            }        });    }    @Override    public int getItemCount() {        return mDatas == null ? 0 : mDatas.size();    }    public static class MyViewHolder extends RecyclerView.ViewHolder {        TextView tv;        public MyViewHolder(View itemView) {            super(itemView);            tv = (TextView) itemView.findViewById(R.id.tv);        }    }    public void addData(int position) {        mDatas.add(position, "新添加的");        mHeights.add( (int) (100 + Math.random() * 300));        notifyItemInserted(position);    }        public void removeData(int position) {        mDatas.remove(position);        notifyItemRemoved(position);    }    public interface OnItemClickLitener {        void onItemClick(View view, int position);        void onItemLongClick(View view, int position);    }    private OnItemClickLitener litener;    public void setLitener(OnItemClickLitener litener) {        this.litener = litener;    }}
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());        }    }}
阅读全文
0 0
原创粉丝点击