Android開發技巧——自訂控制項之使用style
Android開發技巧——自訂控制項之使用style回顧
在上一篇《Android開發技巧——自訂控制項之自訂屬性》中,我講到了如何定義屬性以及在自訂控制項中擷取這些屬性的值,也提到了關於這些屬性除了可以在布局檔案中指定之外,也可以在主題中指定。接下來將分享我所瞭解的關於在主題中指定屬性值的兩種方式。
在主題中指定屬性值
我們在開發過程中,雖然關於自訂控制項學會了如何在布局檔案中指定它的值,以應對不同的需求。但有時還會遇到這樣一種情況:我們希望對某個控制項的屬性,能夠做一個全域的配置,這樣我在本項目中使用它的時候,都是同樣的表現,而不需要每個布局檔案都複製一次屬性的值,而在另一個項目中,我們可以進行另一個全域的配置。
屬性定義及關於實現的思考
在上一篇中,我們講到了自訂屬性,如下所示:
其中format定義了這個屬性的格式,它支援以下這些方式:
boolean 布爾值
color 顏色
dimension 尺寸
enum 枚舉
flag 位或運算
float 浮點值
fraction 百分數
integer 整型值
string 字串
reference 引用某一資源ID
在定義格式時,還可以指定多種格式。比如
而這裡要說的就是reference,引用某一資源ID。
我們可以定義一個屬性,格式為reference,然後在theme中配置它的值為某個style,這樣我們就可以讀取到這個style的屬性。這是我們對這個實現過程的思考。
下面以我以前寫的一個項目IconTabPageIndicator為例,全部代碼見其develop分支。這是一個底部菜單指標,其中每個tab(繼承自TextView)的具體表現我們都希望能夠在style中定義。所以首先我們先定義一個屬性,用於指定這個tab的style:
下面分別說明對這個屬性的兩種使用方式。
在Java代碼中擷取
重寫構造方法。在本例子中,我們的TabView是通過在java代碼中自己new出來的,調用的是構造方法TabView(Context context),所以我們需要重寫這個構造方法,在這個構造方法中調用this(context, null, R.attr.tabView),第三個參數傳入的是R.attr.tabView,即我們定義的style屬性。
public TabView(Context context) { this(context, null, R.attr.tabView); }
然後我們重寫所調用的這個帶defStyle參數的構造方法,因為另外一個構造方法TextView(Context context, AttributeSet attrs)也是調用了它:
public TabView(Context context, AttributeSet attr, int defStyle) { super(context, attr, defStyle); TypedArray a = context.obtainStyledAttributes(attr, R.styleable.TabView, defStyle, 0); iconWidth = a.getDimensionPixelSize(R.styleable.TabView_iconWidth, 0); iconHeight = a.getDimensionPixelSize(R.styleable.TabView_iconHeight, 0); a.recycle(); }
在構造方法中,首先第一行是調用父構造方法。接下來,我們就需要擷取我們自訂的其他屬性了,比如在這個例子中的表徵圖寬高,擷取時調用的方法與昨天所使用的有點不同 ,我們調用的是
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes),第三個參數是我們定義的style屬性,第四個參數則是style資源。在確定一個屬性最終的值的時候,優先順序順序是這樣的:
首先擷取給定的AttributeSet中的屬性值 如果找不到,則去AttributeSet中style(你在寫布局檔案時定義的
style=@style/xxxx)指定的資源擷取 如果找不到,則去
defStyleAttr以及
defStyleRes中的預設style中擷取。 最後去找的是當前
theme下的基礎值。
所以在上面的方法中,我們也可以給第四個參數傳一個我們預設的style(R.style.xxx),當使用者沒有在第三個屬性所指定的style中聲明一些屬性時,就會使用我們第四個參數中的style裡的屬性。
在調用obtainStyledAttributes方法擷取到屬性之後,後面如何使用則可參考前一篇部落格,或本項目。
別人如何使用
理論上,其他人使用的時候,只要寫一個style,然後在他的應用的主題中指定,就可以了。但是通常我們會需要指定許多屬性的值,而這些屬性的值大部分情況下都是通用的。所以我們首先應提供一個良好的style,如下:
在這個style中,我定義了tab文字置中,背景色,字型大小顏色,邊距等。在不重寫其中的屬性的情況下,就能提供一個外觀良好的效果。
然後寫個theme,在其中指定這個style,算是作為一個給其他開發人員學習的樣本:
這裡的tabView就是我們所定義的style屬性,也是我們在構造方法中指定的R.attr.tabView。
如果庫的使用者需求對這style進行修改,只需要寫一個style,繼承自我們的TabViewstyle,重寫裡面的屬性值即可:
當然,還有最重要的一步:必須在自己的項目的主題中指定:
此例子的完整項目請參考Github項目IconTabPageIndicator
在布局檔案中指定style屬性
我們定義的style屬性,除了通過Java代碼來擷取使用之外,也可以直接通過布局檔案來使用。需要使用到的是style屬性。
我們對一個控制項的style屬性,通常的寫法都是:style=@style/xxxxx,或者是指定android系統中的屬性:style=@android:style/xxxx,除此之外,我們也可以用來指定我們所定義的style屬性。
我另一個練習的項目ActionSheet就是使用了這種方式。完整代碼請參見github上該項目地址,這裡僅摘取部分相關的代碼。
ActionSheet是我寫的一個和qq菜單有點像的菜單,我希望菜單的每一項都是可以配置的。由於菜單是通過Dialog來載入,而Dialog是在Java代碼中new出來,所以不能通過在xml中定義各個屬性來完成菜單外觀的配置,因此採用了這種方式。
首先同樣是定義一些屬性,和上面的一樣:
這裡表示的是菜單列表的屬性,取消按鈕的樣式,以及每一項菜單的樣式。然後在我們的菜單布局檔案中,除了不允許配置的屬性我們進行了聲明之外,其他的都是用style屬性來指定,寫法是style=?attr/你所定義的屬性名稱,如下:
同樣在我們的style.xml檔案中,需要定義這幾個style:
下面代碼略...
而庫的使用者,在使用的時候,也需要指定這幾個屬性值:
本篇到此結束,相關項目如下:
IconPageIndicator 開發分支,學習自JakeWharton大神的ViewPagerIndicator ActionSheet,學習自哪個項目我也忘了。