RecyclerView的demo

来源:互联网 发布:深圳冰川网络 编辑:程序博客网 时间:2024/05/18 00:27

作为listview的升级版,这个技能是绝对值得点上的

recyclerview需要导包:compile 'com.android.support:recyclerview-v7:26.0.+'
布局:    <android.support.v7.widget.RecyclerView    //可以设置rv的方向        android:orientation="Vertical"        android:id="@+id/rv"        android:layout_width="match_parent"        android:layout_height="300dp">    </android.support.v7.widget.RecyclerView>
创建adapter继承于RecyclerView.adapter<holder>public class MyAdapter extends RecyclerView.Adapter<MyAdapter.Holder> {    List<String> datas;    public MyAdapter(List<String> datas) {        this.datas = datas;    }    @Override    public int getItemCount() {        return datas.size();    }    //返回holder类    @Override    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {        return new Holder(View.inflate(parent.getContext(),R.layout.tab_item,null));    }    //绑定数据    @Override    public void onBindViewHolder(Holder holder, int position) {        //通过该方法来展示不同类型的item        int type = getItemViewType(position);        switch (type){            case 1:                holder.iv.setImageResource(R.mipmap.ic_launcher);                break;            case 2:                holder.iv.setImageResource(R.mipmap.ic_launcher_round);                break;        }        holder.tv.setText(datas.get(position));        //顺便一提,rv并没有lv中setitemclick()的监听方法,需要监听item事件可以在这里通过        //view.onclick(内部类)的方式设置事件监听    }    //通过该方法可以设置在rv中展示不同类型的item    @Override    public int getItemViewType(int position) {        if ((position%2)==1){            return 1;        }else{            return 2;        }    }    //创建holder类继承于RecyclerView.ViewHolder,并通过传入的view来初始化子控件    public class Holder extends RecyclerView.ViewHolder {        ImageView iv;        TextView tv;        public Holder(View itemView) {            super(itemView);            setView(itemView);        }        public void setView(View view){            iv = view.findViewById(R.id.tab_imageview);            tv = view.findViewById(R.id.tab_textview);        }    }}
展示:    //创建随机长度的数据    private void initData() {        datas=new ArrayList<>();        for (int i = 0; i < 100; i++) {            int times = new Random().nextInt(30);            StringBuilder sb =new StringBuilder();            for (int j = 0; j < times; j++) {                sb.append("哈哈");            }            datas.add(sb.toString()+i);        }    }    private void show() {        MyAdapter ada = new MyAdapter(datas);        rv.setAdapter(ada);        //线性布局        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);        //可以设置方向        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);        rv.setLayoutManager(linearLayoutManager);        rv.setLayoutManager(new GridLayoutManager(this,3));        //瀑布流布局        rv.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));    }

设置recyclerview的分割线

方法一:在item布局中设置margin<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="50dp"              android:orientation="vertical">    <ImageView        android:id="@+id/tab_imageview"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginLeft="10dp"        android:layout_marginRight="10dp"        android:layout_marginTop="10dp"        android:background="#0000ff"    />    <TextView        android:id="@+id/tab_textview"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginBottom="10dp"        //在recyclerview中设置不同的颜色        android:background="#0000ff"        android:textColor="@drawable/selector"    /></LinearLayout>
调用mRecyclerView.addItemDecoration();不过,需要手动实现分割线    //实现分割线    public class DivLineDemo extends RecyclerView.ItemDecoration{        //会在子类被绘制之前调用,所以会在item图层下面        @Override        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {            super.onDraw(c, parent, state);        }        //在子类被绘制之后绘制,所以绘制的图形会覆盖item        @Override        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {            super.onDrawOver(c, parent, state);        }        //像padding和margin,可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。        @Override        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        //每个item距离下方的item有3dp的分割线,实现了类似margin的效果            outRect.set(0,0,0,3);        }    }
网络找来的一份线性布局的分割线demo/** * 调用了系统的分割线,可以在样式中自定义分隔线的样式 */-------------------------------------------------------------------------------------public class DivLine extends RecyclerView.ItemDecoration {    private static final int[] ATTRS = new int[]{            android.R.attr.listDivider    };    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;    private Drawable mDivider;    private int mOrientation;    private DivLine(){}    public DivLine(Context context, int orientation) {        final TypedArray a = context.obtainStyledAttributes(ATTRS);        mDivider = a.getDrawable(0);        a.recycle();        setOrientation(orientation);    }    public void setOrientation(int orientation) {        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {            throw new IllegalArgumentException("invalid orientation");        }        mOrientation = orientation;    }    @Override    public void onDraw(Canvas c, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            drawVertical(c, parent);        } else {            drawHorizontal(c, parent);        }    }    public void drawVertical(Canvas c, RecyclerView parent) {        final int left = parent.getPaddingLeft();        final int right = parent.getWidth() - parent.getPaddingRight();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    public void drawHorizontal(Canvas c, RecyclerView parent) {        final int top = parent.getPaddingTop();        final int bottom = parent.getHeight() - parent.getPaddingBottom();        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 left = child.getRight() + params.rightMargin;            final int right = left + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    @Override    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());        } else {            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);        }    }}-----------------------------------------------------------------------------------在style中自定义分割线的样式<resources>    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">        <item name="colorPrimary">@color/colorPrimary</item>        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>        <item name="colorAccent">@color/colorAccent</item>        //自定义分割线样式        <item name="android:listDivider">@drawable/divider_bg</item>    </style></resources>创建一个shape位图<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"       android:shape="rectangle">    <gradient        android:centerColor="#ff00ff00"        android:endColor="#ff0000ff"        android:startColor="#ffff0000"        android:type="linear"/>    <size android:height="4dp"/></shape>
转自网络,gridlayoutmanger的分割线----------------------------------------------------------------------------------------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());        }    }}----------------------------------------------------------------------------------------

Recycler添加头布局和脚布局

public class HeaderFooterAdapter extends RecyclerView.Adapter<HeaderFooterAdapter.Holder> {    //头布局和脚布局,并添加相应的get set方法    View header;    View footer;    public void setHeader(View view) {        header = view;    }    public void setFooter(View view) {        footer = view;    }    public View getHeader() {        return header;    }    public View getFooter() {        return footer;    }    //普通数据    List<String> datas;    public HeaderFooterAdapter(List<String> datas) {        this.datas = datas;    }    //通过判断头布局和脚布局是否为空,返回的count不同    @Override    public int getItemCount() {        int num = datas.size();        if (header != null)            num++;        if (footer != null)            num++;        return num++;    }    //返回holder类,头布局和脚布局直接返回    @Override    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == 8)            return new Holder(footer);        if (viewType == 9) {            return new Holder(header);        }        return new Holder(View.inflate(parent.getContext(), R.layout.tab_item, null));    }    //绑定数据    @Override    public void onBindViewHolder(Holder holder, int position) {        //通过该方法来展示不同类型的item        int type = getItemViewType(position);        switch (type) {            case 1:                holder.iv.setImageResource(R.mipmap.ic_launcher);                if (header != null)                    holder.tv.setText(datas.get(position - 1));                else                    holder.tv.setText(datas.get(position));                break;            case 2:                holder.iv.setImageResource(R.mipmap.ic_launcher_round);                if (header != null)                    holder.tv.setText(datas.get(position - 1));                else                    holder.tv.setText(datas.get(position));                break;            case 8:                break;            case 9:                break;        }    }    //通过该方法可以设置在rv中展示不同类型的item    @Override    public int getItemViewType(int position) {        if (header != null) {            if (position == 0) {                //9的意思是头布局                return 9;            }        }        if (footer != null) {            //footer不为空,且是最后一位            if (position == getItemCount() - 1) {                //8的意思是脚布局                return 8;            }        }        if ((position % 2) == 1) {            return 1;        } else {            return 2;        }    }    //创建holder类继承于RecyclerView.ViewHolder,并通过传入的view来初始化子控件    public class Holder extends RecyclerView.ViewHolder {        ImageView iv;        TextView tv;        public Holder(View itemView) {            super(itemView);            //如果是头布局和脚布局,则直接返回            if (itemView == header)                return;            if (itemView == footer)                return;            setView(itemView);        }        public void setView(View view) {            iv = view.findViewById(R.id.tab_imageview);            tv = view.findViewById(R.id.tab_textview);        }    }}

自定义布局管理器

对于各种奇葩需求,有时候我们只能自己上了,还好rv中可以自定义layoutmangerpublic class MyLayoutManager extends RecyclerView.LayoutManager {    final MyLayoutManager self = this;    //默认的布局的宽高参数    @Override    public RecyclerView.LayoutParams generateDefaultLayoutParams() {        return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);    }    //布局的入口,这里我们做一个斜着对齐的linearlayoutmanager    @Override    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {        super.onLayoutChildren(recycler, state);        //该方法的作用是分离所有的item的视图,将原本rv中item全部解绑        detachAndScrapAttachedViews(recycler);        int offsetX = 0;        int offsetY = 0;        //获取item个数的方法getItemCount()        for (int i = 0; i < getItemCount(); i++) {            // 根据position获取一个碎片view,可以从回收的view中获取,也可能新构造一个            View scrap = recycler.getViewForPosition(i);            //遍历获取总高度,在处理滚动事件的时候有用            totalHeight+=scrap.getHeight();            //因为已经detach所以可以重新添加            addView(scrap);            // 计算此碎片view包含边距的尺寸            measureChildWithMargins(scrap, 0, 0);            int width = getDecoratedMeasuredWidth(scrap);  // 获取此碎片view包含边距和装饰的宽度width            int height = getDecoratedMeasuredHeight(scrap); // 获取此碎片view包含边距和装饰的高度height            // 布局到RecyclerView容器中,所有的计算都是为了得出任意position的item的边界来布局            layoutDecorated(scrap, offsetX , offsetY, offsetX + width, offsetY + height);            offsetX += width;            offsetY += height;            if (offsetX+width>=getWidth())                offsetX=0;        }    }    //处理垂直方向上的滑动    @Override    public boolean canScrollVertically() {        return true;    }    //总偏移量    int verticalScrollOffset;    //所有item的总高度    int totalHeight;    @Override    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {        //列表向下滚动dy为正,列表向上滚动dy为负,这点与Android坐标系保持一致。        //实际滑动的距离        int travel = dy;        //如果滑动到最顶部,则设置为0        if (verticalScrollOffset + dy < 0) {            travel = 0;        }        //如果滑动到了最底部        else if (verticalScrollOffset + dy > totalHeight - getHeight()) {            travel = totalHeight - getHeight()                    - verticalScrollOffset;        }        //将竖直方向的偏移量+travel        verticalScrollOffset += travel;        // 调用该方法通知view在y方向上移动指定距离,滑动和方向与item滚动的方向相反        offsetChildrenVertical(-travel);        return travel;    }}

recyclerview加载多重item布局

//可惜不能用泛型,需要自己强转public class ParentRecordAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {    List<JsonParentRecord> mDatas = new ArrayList<>();    public void addDatas(List<JsonParentRecord> datas) {        mDatas.addAll(0,datas);    }//通过判断type返回不同的viewholder    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == 0) {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.directormailbox_get_item, parent, false);            ViewHolder0 viewHolder = new ViewHolder0(view);            return viewHolder;        } else {            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.directormailbox_send_item, parent, false);            ViewHolder1 viewHolder = new ViewHolder1(view);            return viewHolder;        }    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        //判断类型,并进行强转        if (holder instanceof ViewHolder0) {              //todo        } else if (holder instanceof ViewHolder1) {               //todo        }    }    @Override    public int getItemCount() {        return mDatas.size();    }    public List<JsonParentRecord> getDatas() {        return mDatas;    }//在这里返回不同类型的type    @Override    public int getItemViewType(int position) {        //0为学生,在左边        return mDatas.get(position).getType();    }//创建多个viewholder类    class ViewHolder0 extends RecyclerView.ViewHolder {        //type0        TextView tv_content_stu;        TextView tv_time_stu;        public ViewHolder0(View layout) {            super(layout);            tv_content_stu = layout.findViewById(R.id.textview_directormailbox_get_coonten);            tv_time_stu = layout.findViewById(R.id.textview_directormailbox_get_time);        }    }    class ViewHolder1 extends RecyclerView.ViewHolder {        //type1        TextView tv_content_parents;        TextView tv_time_parents;        public ViewHolder1(View layout) {            super(layout);            tv_content_parents = layout.findViewById(R.id.textview_directormailbox_send_coonten);            tv_time_parents = layout.findViewById(R.id.textview_directormailbox_send_time);            layout.findViewById(R.id.textview_directormailbox_send_nimingshifou).setVisibility(View.GONE);            layout.findViewById(R.id.textview_directormailbox_send_biaoshi).setVisibility(View.GONE);        }    }}