之前遇到的分割线特别简单,为了简单省事,就是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的左边框的距离,这个距离包括一个或多个分割线宽度)。