編輯:關於Android編程
重新定義分割線Drawable的Bounds
首先,需要清楚一個事實:出現以上情況的矛盾點,是官方ListView的分割線屬性不支持左右留白。所以最佳的解決方案,就是使得官方的分割線支持這種功能,這樣既利於擴展,也利於提高性能。
先來簡單看一下,ListView的源碼是如何實現分割線的功能的。
void drawDivider(Canvas canvas, Rect bounds, int childIndex) {
// This widget draws the same divider for all children
final Drawable divider = mDivider;
divider.setBounds(bounds);
divider.draw(canvas);
}
在onDraw方法中,最終會調用到drawDivider方法。由於分割線是一個Drawable對象,上下左右的位置都是由Rect對象控制的,這個對象通過setBounds方法設置。
這個Rect對象的top和bottom屬性我們是不需要關心的,只需要看left和right兩個屬性,默認情況下left=paddingLeft,right=width-paddingLeft-paddingRight,即表示分割線的起點和終點貫穿ListView的左右兩側。
dispatchDraw方法中可以驗證這一點:
protected void dispatchDraw(Canvas canvas) {
...
if (drawDividers || drawOverscrollHeader || drawOverscrollFooter) {
final Rect bounds = mTempRect;
bounds.left = mPaddingLeft;
bounds.right = mRight - mLeft - mPaddingRight;
...
drawDivider(canvas, bounds, i);
}
...
}
如果我們能將bounds的left和right屬性的值進行修改,那麼就能實現控制分割線的左右邊距了。
既然需要擴展ListView,最常用的方法就是繼承重寫了。不幸的是由於drawDivider方法的訪問控制故並不能被復寫,但值得慶幸的是ListView的Divider對象具有setter和getter方法。
具體的實現邏輯非常簡單,核心是裝飾模式,我就不去詳細說了。
源碼和范例詳見:https://github.com/MegatronKing/DividerSample
用法非常簡單,給ListView分割線擴充了兩個屬性:dividerPaddingLeft和dividerPaddingRight,顧名思義。這兩個屬性值既可以在xml布局中配置也可以在代碼中設置。
layout示例如下:
<com.megatronking.divider.view.DividerListView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:divider="http://schemas.android.com/apk/res-auto"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#99cccccc"
android:dividerHeight="0.5dip"
divider:dividerPaddingLeft="15dip"
divider:dividerPaddingRight="15dip" />
使用inset標簽定義drawable
在Drawable家族中有一個特殊的存在:InsetDrawable,可以定義上下左右四個邊界的留白,InsetDrawable同樣使用了裝飾模式,和方案4的機制有異曲同工之妙。當被裝飾Drawable的Bound值變化時,重新定義Bound。另外,最強大的是可以直接使用xml定義。
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="15dip">
<shape>
<size android:height="0.5dip" />
<solid android:color="#99cccccc" />