Android进阶 RecyclerView自定义分割线的使用

RecyclerView控件的特点:

        从整体上看,RecyclerView架构提供了一种插拔式的体验,它具有高度的解耦、异常的灵活性和更高的效率,通过设置它提供的不同LayoutManager、ItemDecoration、ItemAnimator可实现更加丰富的效果,但是RecyclerView也有缺点:设置列表的分割线时需要自定义,另外列表的点击事件需要自己实现。

添加依赖:

implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'

使用RecyclerView:

    private RecyclerView recyclerView;
    private List<String> mList;
    private HomeAdapter homeAdapter;
    private LinearLayoutManager manager;
      manager=new LinearLayoutManager(this);
      //manager.setOrientation(LinearLayoutManager.HORIZONTAL);
      recyclerView.setLayoutManager(manager);//设置布局管理器用于设置条目的排列方式(默认垂值)
      //添加分割线
      recyclerView.addItemDecoration(new 
      DividerItemDecoration(MainActivity.this,DividerItemDecoration.VERTICAL_LIST));
      recyclerView.setItemAnimator(new DefaultItemAnimator());//设置item增加和删除时的动画
      homeAdapter=new HomeAdapter(this,mList);//传出数据
      recyclerView.setAdapter(homeAdapter);//添加adapter

View布局:

主布局activity_main.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/id_recyclerView"
        android:divider="#FFB900"
        android:dividerHeight="1dp"/>
    <!--android:divider:设置分割线显示颜色-->
</LinearLayout>

子布局item_recycler.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="@android:color/white"
    android:layout_height="wrap_content"
    android:layout_margin="2dp">

    <TextView
        android:id="@+id/tv_item"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="moon"/>
</FrameLayout>

Adapter适配器和分割线:

       Adapter最大的改进就是对ViewHolder进行了封装定义,我们只需要自定义一个ViewHolder继承RecyclerView.ViewHolder就可以了,另外,Adapter继承了RecyclerView.Adapter,在onCreateViewHolder中加载条目布局,在onBindViewHolder中将视图与数据进行绑定。

1、类似于ListView式布局所对应的适配器HomeAdapter.java文件:

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.dpl.recyclerviewdemo.R;
import java.util.List;

/**
 * 功能:数据适配器
 */
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> {

    private Context context;
    private List<String> mList;
    private OnItemClickListener onItemClickListener;

    public HomeAdapter(Context context, List<String> mList){//传入数据
        this.context=context;
        this.mList=mList;
    }
    public void removeData(int position){    //移除数据
        mList.remove(position);
        notifyItemRemoved(position);
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_recycler,viewGroup,false));
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, final int i) {
        myViewHolder.textView.setText(mList.get(i));
        if (onItemClickListener!=null){
            myViewHolder.textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos=myViewHolder.getLayoutPosition();
                    onItemClickListener.onItemClick(myViewHolder.textView,pos);
                }
            });
            myViewHolder.textView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos=myViewHolder.getLayoutPosition();
                    onItemClickListener.onItemLongClick(myViewHolder.textView,pos);
                    return false;
                }
            });
        }
    }
    @Override
    public int getItemCount() {
        return mList.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        MyViewHolder(@NonNull View itemView) {
            super(itemView);
            textView=itemView.findViewById(R.id.tv_item);
        }
    }

    /**
     * 自定义列表条目的点击事件
     */
    public interface OnItemClickListener{
        void onItemClick(View view,int position);
        void onItemLongClick(View view,int position);
    }
    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener=onItemClickListener;
    }

}

设置类似于ListView的自定义分割线DividerItemDecoration.java文件:

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.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * 功能:绘制类似ListView 的RecyclerView子布局item的分割线
 */

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS=new int[]{android.R.attr.listDivider};//android.R.attr.listDivider作为Item间的系统默认分割线,并且支持横向和纵向
    public static final int HORIZONTAL_LIST= LinearLayoutManager.HORIZONTAL;
    public static final int VERTICAL_LIST=LinearLayoutManager.VERTICAL;
    private Drawable mDivider;//Drawable就是一个可画的对象,其可能是一张位图(BitmapDrawable),也可能是一个图形(ShapeDrawable),象
    private int mOrientation;
    public DividerItemDecoration(Context context,int orientation){
        final TypedArray a=context.obtainStyledAttributes(ATTRS);
        //用TypedArray获取XML中的属性,通过Context的obtainStyledAttributes方法创建TypedArray,然后用getXXX来获取对应的属性。
        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(@NonNull Canvas c, @NonNull RecyclerView parent) {//根据传进来的orientation进行绘制
        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);//获取子视图
            RecyclerView v=new RecyclerView(parent.getContext());
            final RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) child.getLayoutParams();//获取子控件的layoutParams参数
            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);
            RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) child.getLayoutParams();
            final int left=child.getLeft()+params.leftMargin;
            final int right=left+mDivider.getIntrinsicHeight();//getIntrinsicWidth()和getIntrinsicHeight(),用来取得Drawable的固有的宽度和高度(dp)。
            mDivider.setBounds(left,top,right,bottom);//四参数指的是drawable将在被绘制在canvas的哪个矩形区域内。
            mDivider.draw(c);
        }
    }

    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent){//设置item分割线的size
        if (mOrientation==VERTICAL_LIST){
            outRect.set(0,0,0,mDivider.getIntrinsicHeight());//设置矩形参数
        }else{
            outRect.set(0,0,mDivider.getIntrinsicWidth(),0);
        }
    }
}

运行图:

 2、实现GridView

适配器使用HomeAdapter.java文件。

自定义Item分割线DividerGridItemDecoration.java文件:


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.annotation.NonNull;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

/**
 * 功能:GridViewItem分割线
 */
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 array=context.obtainStyledAttributes(ATTRS);
        mDivider=array.getDrawable(0);
        array.recycle();//回收
    }

    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        drawHorizontal(c,parent);
        drawVertical(c,parent);
    }
    private int getSpanCount(RecyclerView parent){
        //获取列数
        int spanCount=-1;
        RecyclerView.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 position,int spanCount,int childCount){
        RecyclerView.LayoutManager layoutManager=parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager){
            if ((position+1)%spanCount==0){//如果是最后一列,则不需要绘制右边
                 return true;
            }
        }else if (layoutManager instanceof StaggeredGridLayoutManager){
            int orientation=((StaggeredGridLayoutManager)layoutManager).getOrientation();
            if (orientation==StaggeredGridLayoutManager.VERTICAL){
                if ((position+1)%spanCount==0){//如果是最后一列,则不需要绘制右边
                    return true;
                }
            }else {
                childCount=childCount-childCount%spanCount;
                if (position>=childCount)//如果是最后一列,则不需要绘制右边
                    return true;
            }
        }
        return false;
    }
    private boolean isLastRaw(RecyclerView parent,int position,int spanCount,int childCount){
        RecyclerView.LayoutManager layoutManager=parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager){
            childCount=childCount-childCount%spanCount;
            if (position>=childCount)//如果是最后一行,则不需要绘制底部
                return true;
        }else if (layoutManager instanceof  StaggeredGridLayoutManager){
            int orientation=((StaggeredGridLayoutManager)layoutManager).getOrientation();
            //StaggeredGridLayoutManager且纵向滚动
            if (orientation==StaggeredGridLayoutManager.VERTICAL){
                childCount=childCount-childCount%spanCount;
                //如果是最后一行,则不需要绘制底部
                if (position>=childCount)
                    return true;
            }else{//StaggeredGridLayoutManager且横向滚动
                //如果是最后一行,则不需要绘制底部
                if ((position+1)%spanCount==0){
                    return true;
                }
            }
        }
        return false;
    }
    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());
        }
    }
}

运行图:

3、实现瀑布流StaggeredGridView.java文件:

Adapter适配器:StaggeredHomeAdapter.java文件

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.dpl.recyclerviewdemo.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 功能:瀑布流的适配器
 */
public class StaggeredHomeAdapter extends RecyclerView.Adapter<StaggeredHomeAdapter.MyViewHolder> {
    private List<String> mDatas;
    private LayoutInflater mInflater;
    private List<Integer> mHeights;
    private OnItemClickListener onItemClickListener;

    public interface OnItemClickListener{
        void onItemClick(View view,int position);
        void onItemLongClick(View view,int position);
    }
    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener=onItemClickListener;
    }

    public StaggeredHomeAdapter(Context context,List<String> datas){
        mInflater=LayoutInflater.from(context);
        mDatas=datas;
        mHeights=new ArrayList<Integer>();
        for (int i=0;i<mDatas.size();i++){
            mHeights.add((int)(100+Math.random()*300));
        }
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        return new MyViewHolder(mInflater.inflate(R.layout.item_recycler,viewGroup,false));
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, int i) {
        ViewGroup.LayoutParams lp=myViewHolder.tv.getLayoutParams();
        lp.height=mHeights.get(i);
        myViewHolder.tv.setLayoutParams(lp);
        myViewHolder.tv.setText(mDatas.get(i));
        //如果设置了回调,则设置点击事件
        if (onItemClickListener!=null){
            myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos=myViewHolder.getLayoutPosition();
                    onItemClickListener.onItemClick(myViewHolder.itemView,pos);
                }
            });
            myViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos=myViewHolder.getLayoutPosition();
                    onItemClickListener.onItemLongClick(myViewHolder.itemView,pos);
                    removeData(pos);
                    return false;
                }
            });
        }
    }

    public void addData(int position){
        mDatas.add(position,"Insert One");
        mHeights.add((int)(100+Math.random()*300));
        notifyItemInserted(position);
    }
    public void removeData(int position){
        mDatas.remove(position);
        notifyItemRemoved(position);
    }
    @Override
    public int getItemCount() {
        return mDatas.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tv;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tv=itemView.findViewById(R.id.tv_item);
        }
    }
}

 

瀑布流的分割线使用DividerGridItemDecoration.java文件。

运行图:

 

Control控制器:MainActivity.java文件

import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.widget.Toast;

import com.dpl.recyclerviewdemo.adapter.HomeAdapter;
import com.dpl.recyclerviewdemo.adapter.StaggeredHomeAdapter;
import com.dpl.recyclerviewdemo.util.DividerGridItemDecoration;
import com.dpl.recyclerviewdemo.util.DividerItemDecoration;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private List<String> mList;
    private HomeAdapter homeAdapter;
    private LinearLayoutManager manager;
    private StaggeredHomeAdapter staggeredHomeAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();

    }
    private void initData(){//初始化数据
        mList=new ArrayList<>();
        for (int i=1;i<100;i++){
            mList.add(i+"");
        }
    }
    private void initView(){   //初始化view
        recyclerView=this.findViewById(R.id.id_recyclerView);
        //设置ListView
//        setListView();
        //设置GridView
//        setGridView();
        //设置瀑布流StaggeredGridView
        setWaterfallView();
    }
    public void setListView(){
        manager=new LinearLayoutManager(this);
        //manager.setOrientation(LinearLayoutManager.HORIZONTAL);
        recyclerView.setLayoutManager(manager);
        recyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this,DividerItemDecoration.VERTICAL_LIST));
        recyclerView.setItemAnimator(new DefaultItemAnimator());//设置item增加和删除时的动画
        homeAdapter=new HomeAdapter(this,mList);//传出数据
        setLister();
        recyclerView.setAdapter(homeAdapter);//添加adapter
    }
    public void setGridView(){
        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));
        recyclerView.addItemDecoration(new DividerGridItemDecoration(MainActivity.this));
        recyclerView.setItemAnimator(new DefaultItemAnimator());//设置item增加和删除时的动画
        homeAdapter=new HomeAdapter(this,mList);//传出数据
        setLister();
        recyclerView.setAdapter(homeAdapter);//添加adapter
    }

    public void setWaterfallView(){
        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));
        recyclerView.addItemDecoration(new DividerGridItemDecoration(MainActivity.this));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        staggeredHomeAdapter=new StaggeredHomeAdapter(this,mList);
        staggeredHomeAdapter.setOnItemClickListener(new StaggeredHomeAdapter.OnItemClickListener(){
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this,"点击第"+(position+1)+"条",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, final int position) {
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle("确认删除吗?")
                        .setNegativeButton("取消",null)
                        .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                staggeredHomeAdapter.removeData(position);
                            }
                        });
            }
        });
        recyclerView.setAdapter(staggeredHomeAdapter);
    }
    public void setLister(){
        homeAdapter.setOnItemClickListener(new HomeAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this,"点击第"+(position+1)+"条",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, final int position) {
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle("确认删除吗?")
                        .setNegativeButton("取消",null)
                        .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                homeAdapter.removeData(position);
                            }
                        });
            }
        });
    }
}

参考博客:

https://blog.csdn.net/crazyZhangxl/article/details/81043205

https://blog.csdn.net/dodod2012/article/details/79030559

https://blog.csdn.net/SuperBigLw/article/details/53404489

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值