RecyclerView的demo

作为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中可以自定义layoutmanger

public 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);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值