在上一篇RecyclerView系列之一:實(shí)現(xiàn)常見(jiàn)的ListView效果簡(jiǎn)單介紹了使用RecyclerView如何實(shí)現(xiàn)ListView的效果瓶珊,但是我們也發(fā)現(xiàn)了,效果圖中沒(méi)有分隔線,今天將介紹如何為RecyclerView添加分隔線.
一、如何添加分隔線
嗯佃乘,首先有兩種比較low的方式:
1、為item布局設(shè)置一個(gè)背景色驹尼,再為item根標(biāo)簽設(shè)置一個(gè)margin或者padding趣避,這樣就形成了分隔線的效果.
2、在Item布局文件最后加一條橫線新翎,為它設(shè)置一個(gè)背景色程帕,形成分隔線的效果.
然后就是正式的寫(xiě)法了:
3、RecyclerView中可以通過(guò)addItemDecoration()方法添加分割線地啰, 該方法的參數(shù)為RecyclerView.ItemDecoration愁拭,該類為抽象類,官方目前只提供了一個(gè)實(shí)現(xiàn)類DividerItemDecoration.
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private LinearLayoutManager layoutManager;
private MainAdapter mAdapter;
private List<String> mDatas;
private DividerItemDecoration mDivider;//分隔線
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
//初始化分隔線髓绽、添加分隔線
mDivider = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(mDivider);
mAdapter = new MainAdapter(this,mDatas);
mRecyclerView.setAdapter(mAdapter);
}
private void initData() {
mDatas = new ArrayList<>();
for (int i = 'A'; i < 'Z'; i++) {
mDatas.add("" + (char) i);
}
}
}
現(xiàn)在我們?cè)賮?lái)看一下效果圖:
看起來(lái)還行敛苇,但是萬(wàn)一這種效果不是我們需要的怎么辦?所以我們應(yīng)該知道RecyclerView是如何畫(huà)出分隔線的
二顺呕、抽象類RecyclerView.ItemDecoration源碼
public static abstract class ItemDecoration {
public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
}
@Deprecated
public void onDraw(Canvas c, RecyclerView parent) {
}
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
}
@Deprecated
public void onDrawOver(Canvas c, RecyclerView parent) {
}
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
}
當(dāng)我們調(diào)用addItemDecoration()方法添加decoration的時(shí)候枫攀,RecyclerView就會(huì)調(diào)用該類的onDraw方法去繪制分隔線,也就是說(shuō):分隔線是繪制出來(lái)的. 下面來(lái)了解分隔線是如何繪制出來(lái)的.
三株茶、理解分隔線是如何繪制的
系統(tǒng)默認(rèn)實(shí)現(xiàn)類DividerItemDecoration涉及到clipToPadding屬性来涨、畫(huà)布的裁剪一些知識(shí),不太容易理解启盛,也不方便修改蹦掐,這里介紹網(wǎng)上通用的實(shí)現(xiàn).
首先要理解一個(gè)概念:分隔線本質(zhì)是一個(gè)矩形,這個(gè)“線”是有長(zhǎng)度和寬度的.
/**
* 默認(rèn)分隔線實(shí)現(xiàn)類只支持布局管理器為 LinearLayoutManager
*/
public class CommonItemDecoration extends RecyclerView.ItemDecoration {
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
//使用系統(tǒng)主題中的R.attr.listDivider作為Item間的分割線
private static final int[] ATTRS = new int[]{ android.R.attr.listDivider};
private Drawable mDivider;
private int mOrientation;//布局方向僵闯,決定繪制水平分隔線還是豎直分隔線
private final Rect mBounds = new Rect();
public CommonItemDecoration (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 && orientation != VERTICAL) {
throw new IllegalArgumentException(
"Invalid orientation. It should be either HORIZONTAL or VERTICAL");
}
mOrientation = orientation;
}
/**
* 一個(gè)app中分隔線不可能完全一樣卧抗,你可以通過(guò)這個(gè)方法傳遞一個(gè)Drawable 對(duì)象來(lái)定制分隔線
*/
public void setDrawable(@NonNull Drawable drawable) {
if (drawable == null) {
throw new IllegalArgumentException("Drawable cannot be null.");
}
mDivider = drawable;
}
/**
* 畫(huà)分隔線
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (parent.getLayoutManager() == null) {
return;
}
if (mOrientation == VERTICAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
/**
* 在LinearLayoutManager方向?yàn)閂ertical時(shí),畫(huà)分隔線
*/
public void drawVertical(Canvas canvas, RecyclerView parent) {
final int left = parent.getPaddingLeft();//★分隔線的左邊 = paddingLeft值
final int right = parent.getWidth() - parent.getPaddingRight();//★分隔線的右邊 = RecyclerView 寬度-paddingRight值
//分隔線不在RecyclerView的padding那一部分繪制
final int childCount = parent.getChildCount();//★分隔線數(shù)量=item數(shù)量
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);//確定是第幾個(gè)item
final RecyclerView.LayoutParams params =(RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;//★分隔線的上邊 = item的底部 + item根標(biāo)簽的bottomMargin值
final int bottom = top + mDivider.getIntrinsicHeight();//★分隔線的下邊 = 分隔線的上邊 + 分隔線本身高度
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
}
/**
* 在LinearLayoutManager方向?yàn)镠orizontal時(shí)鳖粟,畫(huà)分隔線
* 理解了上面drawVertical()方法這個(gè)方法也就理解了
*/
public void drawHorizontal(Canvas canvas, 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(canvas);
}
}
/**
* 獲取Item偏移量
* 此方法是為每個(gè)Item四周預(yù)留出空間社裆,從而讓分隔線的繪制在預(yù)留的空間內(nèi)
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
if (mOrientation == VERTICAL) {//豎直方向的分隔線:item向下偏移一個(gè)分隔線的高度
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {//水平方向的分隔線:item向右偏移一個(gè)分隔線的寬度
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
四、更改分隔線的樣式
DividerItemDecoration畫(huà)的分割線是讀取系統(tǒng)的屬性android.R.attr.listDivider向图,使用系統(tǒng)的listDivider好處就是就是方便我們?nèi)ルS意的分隔線的樣式
1泳秀、找到res/values/styles.xml,在其中聲明android:listDivider屬性,然后使用我們自己的樣式
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:listDivider">@drawable/my_divider</item>
</style>
</resources>
2榄攀、在res/drawable目錄下聲明我們自己的樣式my_divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:centerColor="#ff00ff"
android:endColor="#00ff00"
android:startColor="#0000ff"
android:type="linear" />
<size android:height="4dp"/>
</shape>
再來(lái)看一下效果圖
3嗜傅、當(dāng)然,這樣一修改就改變整個(gè)app中的分隔線效果了檩赢,如果只是想改變某個(gè)列表中的分隔線效果吕嘀,完全可以通過(guò)分隔線的setDrawable方法來(lái)修改
mDivider = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
mDivider.setDrawable(getResources().getDrawable(R.drawable.my_divider));
mRecyclerView.addItemDecoration(mDivider);
這樣一來(lái),不同的列表就可以使用不同的分隔線效果了.