編輯:關於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" />