掌握recycleview的分割线ItemDecoration的画法-------网格分割线

     之前遇到的分割线特别简单,为了简单省事,就是item布局里面加个描边的背景,虽然任务完成了,总感觉特别消耗cpu,遇到大量数据的加载,体验效果就特别不好。特地在网上查询了各种资料,作为刚开始话分割线的小白,看上面的资料特别懵逼,不知道ItemDecoration里面重写的方法到底是干什么的,比如说onDraw怎么计算各个分割线的,getItemOffsets表示偏移量,就是弄不懂,特地做了个有意思的实验,掌握了分割线的画法,特此记录以下,让还不明白的同学理解这个东东。

我在 这里只展示网格分割线的画法。不说废话,直接上代码。先定义一个drawable风格线的样式,代码如下,文件名为grid_line.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@android:color/holo_red_light"></solid>
    <size android:height="3dp"
        android:width="3dp"></size>
</shape>

然后就是分割线的代码

package com.dxy.myapplication;

import android.content.Context;
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.view.View;

public class GridDivider extends RecyclerView.ItemDecoration {


    private Drawable mDividerDrawable;

    private int lineHeight;


    public GridDivider(Context context, int resourceId) {
        mDividerDrawable = context.getResources().getDrawable(resourceId);
        lineHeight=mDividerDrawable.getIntrinsicHeight();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
//        final int childrenSize=parent.getChildCount();
//        final int spanCount=getSpanCount(parent);
//        for (int i=0;i<childrenSize;i++){
//            drawHorizantolLine(c,parent,spanCount,i);
//            drawVerticalLine(c,parent,spanCount,i);
//        }
    }

    private void drawHorizantolLine(Canvas c, RecyclerView parent,int spanCount,int index) {
        final View child=parent.getChildAt(index);
        final RecyclerView.LayoutParams layoutParams=(RecyclerView.LayoutParams)child.getLayoutParams();
        final int left=child.getLeft()-layoutParams.leftMargin;
        final  int right=child.getRight()+layoutParams.rightMargin;
        int top=0;
        int bottom=0;
        if (index/spanCount==0){
            top=child.getTop()-layoutParams.topMargin-lineHeight;
            bottom=top+lineHeight;
            mDividerDrawable.setBounds(left,top,right,bottom);
            mDividerDrawable.draw(c);
        }
        top=child.getBottom()+layoutParams.bottomMargin;
        bottom=top+lineHeight;
        mDividerDrawable.setBounds(left,top,right,bottom);
        mDividerDrawable.draw(c);
    }
    private void drawVerticalLine(Canvas c, RecyclerView parent,int spanCount,int index) {
        final View child=parent.getChildAt(index);
        final RecyclerView.LayoutParams layoutParams=(RecyclerView.LayoutParams)child.getLayoutParams();
        final int top=child.getTop()-layoutParams.topMargin-lineHeight;
        final int bottom=child.getBottom()+lineHeight+layoutParams.bottomMargin;

        int left=0;
        int right=0;
        if (index%spanCount==0){
            left=child.getLeft()-layoutParams.leftMargin-lineHeight;
            right=left+lineHeight;
            mDividerDrawable.setBounds(left,top,right,bottom);
            mDividerDrawable.draw(c);
        }
        left=child.getRight()+layoutParams.rightMargin;
        right=left+lineHeight;
        mDividerDrawable.setBounds(left,top,right,bottom);
        mDividerDrawable.draw(c);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

        int itemPosition = parent.getLayoutManager().getPosition(view);
        int spanCount = getSpanCount(parent);
        outRect.left = lineHeight;
        outRect.top = lineHeight;
        outRect.right = lineHeight;
        outRect.bottom = lineHeight;
        if (itemPosition != 0) {
            if (itemPosition / spanCount == 0) {
                outRect.left = 0;
            } else {
                if (itemPosition % spanCount == 0) {
                    outRect.top = 0;
                } else {
                    outRect.left = 0;
                    outRect.top = 0;
                }
            }
        }
    }
    private int getSpanCount(RecyclerView parent){
        int spanCount=-1;
        RecyclerView.LayoutManager layoutManager=parent.getLayoutManager();
        if (layoutManager instanceof  GridLayoutManager){
            spanCount=((GridLayoutManager) layoutManager).getSpanCount();
        }
        return  spanCount;
    }
}

因为要展示recycleview的分割线,在此定义item布局文件,文件名为recycle_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:background="@android:color/white">
    <TextView
        android:id="@+id/tittle"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:text="你好"
        android:textColor="@android:color/darker_gray"
        android:gravity="center"
        android:textSize="20sp"/>
</LinearLayout>

注意这里item有背景颜色哦,待会会去掉。

然后简单定义个adapter,名为MyAdapter,代码如下

package com.dxy.myapplication.okhttp;

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

import com.dxy.myapplication.R;

import java.util.ArrayList;


public class MyAdapter extends RecyclerView.Adapter <MyAdapter.MyHolder>{

    private Context mContext;

    private ArrayList<String> arrayList;

    public MyAdapter(Context context,ArrayList<String> arrayList) {
        mContext=context;
        this.arrayList=arrayList;
    }

    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MyHolder(LayoutInflater.from(mContext).inflate(R.layout.recycle_item,null));
    }

    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
        holder.tittle.setText(arrayList.get(position));
    }


    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    public static class MyHolder extends RecyclerView.ViewHolder{
        TextView tittle;
        public MyHolder(View itemView) {
            super(itemView);
            tittle=itemView.findViewById(R.id.tittle);
        }
    }
}

然后就是MainActivity的布局文件,recycleview有背景颜色哦,待会会去掉。布局文件名为activity_main.xml

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

 <android.support.v7.widget.RecyclerView
     android:id="@+id/recycle_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@android:color/holo_green_light">

 </android.support.v7.widget.RecyclerView>

</LinearLayout>

然后就是MainActivity的代码

package com.dxy.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.dxy.myapplication.okhttp.MyAdapter;

import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {


 private RecyclerView recyclerView;

 private MyAdapter myAdapter;

 private ArrayList<String> arrayList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView=findViewById(R.id.recycle_view);
        GridLayoutManager gridLayoutManager=new GridLayoutManager(this,3);
        recyclerView.setLayoutManager(gridLayoutManager);
        recyclerView.addItemDecoration(new GridDivider(this,R.drawable.grid_line));
        init();
        myAdapter=new MyAdapter(this,arrayList);
        recyclerView.setAdapter(myAdapter);
    }

    private void init(){
        arrayList=new ArrayList<>();
        for (int i=0;i<500;i++){
            arrayList.add(""+(i+1));
        }
    }

}

看看运行结果:

我们可以看到,这个时候我们把GridDivider里面的onDraw方法的代码注释掉了,也就是没有画分割线,此时recycleview的背景色为绿色,item布局的背景色为白色,也就是说,这个时候每个item布局与其他的相邻布局间隔为1个分割线的宽度,只是我们没有在onDraw方法里面画分割线的颜色,只是通过getItemOffsets的方式让每相邻的item布局预留了一个分割线的偏移量。意思就是说在onDraw方法里面画分割线的时候,每个子布局的getLeft()的距离就包括了分割线的宽度。

然后我们把GridDivider里面onDraw的注释代码放开,并且把recycleview的背景色去掉,把item布局的背景色去掉,再次运行下app,结果如下

onDraw方法,说白了就是描边。此时getItemOffsets已经运行,分割线的位置和item布局已经在recycleview里面排布好,onDraw方法做的就是在分割线的位置涂上你想要的颜色。(也就是在onDraw方法里面,每个子view的到recycleview父布局的距离getTop,getLeft,getBottom,getRight.拿一个来说吧,我在这里针对网格分割线,比如getLeft,表示子view左边框到recycleview的左边框的距离,这个距离包括一个或多个分割线宽度)。

猜你喜欢

转载自blog.csdn.net/dxyadc/article/details/68215722
今日推荐