Android中一種巧妙的drawable.xml替代方案分享
前言
在開發(fā)中我們經(jīng)常要使用圖片或者drawable文件夾下的xml,來實現(xiàn)一些效果,Drawable的用法都和xml相關,我們可以使用shape、layer-list等標簽繪制一些背景,還可以通過selector標簽定義View的狀態(tài)的效果等。當然了基本每個標簽都對應于一個真正的實體類。
所有drawable.xml對應的Java類如下

如何維護(替換)drawable xml是android開發(fā)中一個老生常談的話題。按照標準的Android布局開發(fā)模式,我們不得不為各種UI效果新建不同的xml文件進行描述,哪怕是簡單的一個圓角。隨著項目迭代,成百上千的xml連同那模棱兩可的文件名,不僅讓開發(fā)者復用或清理的成本難以估計,還使得項目體積急劇增大。因此,下面我們探索一種原理巧妙、適配全面的drawable替代方案。
下面話不多說了,來一起看看詳細的介紹吧
傳統(tǒng)方案總結
我們先概括下目前市面上已有的方案,大致分為兩種實現(xiàn)方式。
一種是繼承某個(或某幾個)常用的控件,然后將drawable.xml中的常用屬性作為當前控件的自定義屬性,最后在控件內(nèi)部動態(tài)生成drawable作為該控件的背景。這種方案的優(yōu)點很明顯:能直觀地將drawable效果描述作為控件的屬性定義在布局xml中,具有很好的可讀性;但是缺點也不可忽視,這些屬性并不能應用到任意控件,導致在很多時候還是不得不創(chuàng)建drawable.xml文件。
另一種方案則是將drawable的常用屬性封裝為代碼API,以動態(tài)的方式在代碼中生成并賦值給控件。這種方案理論上完全拋棄了drawable.xml,可以適配任意控件,但是若想完全以這種方式達到完全替換xml,個人覺得不可能,代碼量大,關聯(lián)性低是其最大的缺點,單看布局,無從知曉該控件的最終效果。不過,如果兩相結合,作為對第一種方案的補充倒是一個不錯的方案。
新方案探索
上述兩種方案各有千秋,但都無法完全解決問題,我們對上述兩種方案進行分析,提出以下問題:為什么不能有一種「既具有高可讀性,又能全面適配」的drawable.xml替代方案呢?也就是說能同時兼顧前面提到的兩種方案的優(yōu)點,高可讀性意味著對drawable的描述需要作為屬性定義在布局文件中、全面適配意味這些屬性對任意控件都有效。思來想去,答案似乎只有一個:DataBinding。說到這里,可能有些朋友已經(jīng)隱隱猜到了,不過別急,容我娓娓道來。
DataBinding是Android官方推出的數(shù)據(jù)綁定庫,盡管已有數(shù)年,但是我估計仍有部分開發(fā)者還沒有接觸甚至有些抵觸,具體就不細說,但是我希望你暫且能擁抱它,繼續(xù)閱讀。
數(shù)據(jù)綁定讓數(shù)據(jù)變化能直接反映到布局中,對于控件已有的屬性,例如TextView的android:text屬性,一旦通過DataBinding綁定:
<TextView
android:text="@{name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
在運行時內(nèi)部就會調(diào)用TextView內(nèi)部的setText方法。其實現(xiàn)原理的關鍵就是DataBinding通過提供的@BindingAdapter注解,該注解將任意指定的屬性和任意指定的方法關聯(lián),DataBinding會在編譯的時候動態(tài)生成的調(diào)用關系,而對于常用的控件,DataBinding已經(jīng)預置了對應的注解方法,例如以下就是TextView的setText方法:
@BindingAdapter("android:text")
public static void setText(TextView view, CharSequence text) {
final CharSequence oldText = view.getText();
if (text == oldText || (text == null && oldText.length() == 0)) {
return;
}
if (text instanceof Spanned) {
if (text.equals(oldText)) {
return; // No change in the spans, so don't set anything.
}
} else if (!haveContentsChanged(text, oldText)) {
return; // No content changes, so don't set anything.
}
view.setText(text);
}
我們需要關注的就是這個@BindingAdapter注解,「任意指定的屬性」這個屬性并非特指我們在布局中Android提供的標準屬性,也就是說,我們可以提供任意字符串作為屬性,而任意方法很好理解,上面的代碼片段很好的表達了這個意思,我們唯一需要關注的就是這個方法的參數(shù):第一個參數(shù)是指定注解中的屬性的作用域,后面的參數(shù)則是和注解所聲明的屬性一一對應,那么結合到我們本文的主題,答案也就呼之欲出了:
新方案實現(xiàn)
提供一個用@BindingAdapter注解的方法,作用域指定為View(即任意控件);參數(shù)約定為drawable.xml中的屬性,不就達到了目的嗎。是否是感覺到一絲絲巧妙?既然方案有了,下面我們來看具體實現(xiàn)。
限于drawable屬性的豐富性,本文以常用的屬性solid 和 corner為例展開。如以下片段所示:
@BindingAdapter(value = {
"drawable_solidColor",
"drawable_radius",
}, requireAll = false)
public static void setViewBackground(View v, int color, int radius) {
GradientDrawable drawable = new GradientDrawable();
drawable.setColor(color);
drawable.setCornerRadius(radius);
view.setBackground(drawable);
}
上面代碼片段定義了兩個屬性:drawable_solidColor, drawable_radius,分別表示solid的color和corner的radius屬性,也就是說稍后我們就就可以在布局文件中為每個View都指定該屬性了;
這里可能有朋友會產(chǎn)生疑問,drawable的屬性那么多,這里只定義了兩個還好,如果把所有的drawable屬性都定義,那豈不是每個控件都要把每個屬性都指定一次,即使不需要。所以還需要提一下requireAll參數(shù),它表示是否需要每個屬性都必須綁定了數(shù)據(jù)才會調(diào)用setViewBackground方法,設置為false后,就可以在布局文件中只指定需要的屬性即可。
以上幾行代碼完成了基本定義,下面我們來看看如何使用:
<layout>
<TextView
drawable_radius="@{10}"
drawable_solidColor="@{0xffff0000}"
android:layout_width="60dp"
android:layout_height="60dp" />
<layout/>
不用懷疑,就是這么簡單,即使這里不貼出效果圖,我想大家腦海中已經(jīng)浮現(xiàn)出來了,是不是覺得一目了然?以此類推,其它的drawable屬性也可以通過本方案逐一實現(xiàn)。
總結
回顧本文,并沒有任何復雜的代碼或高深的邏輯組合,僅提出一種巧妙的drawable.xml替代方案,具有「既具有高可讀性,又能全面適配」的特點。
從成本來說,本方案應該是最低的(特別是對一些已經(jīng)在使用DataBinding的項目):只需要定義一個方法即可,而效果卻是最優(yōu)的:理論來講,實現(xiàn)該方案后,可以減少99%的drawable.xml創(chuàng)建。
如果非要說出本方案的缺點,那么它的實現(xiàn)原理所依賴的核心庫DataBinding可能是有些開發(fā)者所不能接受的。
讀到這里,是否覺得意猶未盡?沒錯,我已依據(jù)本文的方案替大家整理好了幾乎所有常用的drawable屬性提交到了GitHub,核心依然是只有一個方法,直接可用。
Github地址:https://github.com/whataa/noD...(本地下載)
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- Android RippleDrawable 水波紋/漣漪效果的實現(xiàn)
- Android自定義Drawable之在Drawable中部指定透明區(qū)域方法示例
- 淺談Android中Drawable使用知識總結
- Android開發(fā)基于Drawable實現(xiàn)圓角矩形的方法
- Android自定義Drawable實現(xiàn)圓角效果
- Android Bitmap和Drawable的對比
- Android Drawable和Bitmap的轉(zhuǎn)換實例詳解
- Android DrawableTextView圖片文字居中顯示實例
- Android Drawable必備知識小結
- Android drawable微技巧,你不知道的drawable細節(jié)
相關文章
解決WebView通過URL加載H5界面出現(xiàn)空白的問題
這篇文章主要介紹了解決WebView通過URL加載H5界面出現(xiàn)空白的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android中利用NetworkInfo判斷網(wǎng)絡狀態(tài)時出現(xiàn)空指針(NullPointerException)問題的解決
這篇文章主要介紹了Android中利用NetworkInfo判斷網(wǎng)絡狀態(tài)時出現(xiàn)空指針(NullPointerException)問題的解決方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11
Android App的運行環(huán)境及Android系統(tǒng)架構概覽
這篇文章主要介紹了Android App的運行環(huán)境及Android系統(tǒng)架構概覽,并對應用程序進程間隔離機制等知識點作了介紹,需要的朋友可以參考下2016-03-03
Android網(wǎng)絡監(jiān)聽和網(wǎng)絡判斷示例介紹
大家好,本篇文章主要講的是Android網(wǎng)絡監(jiān)聽和網(wǎng)絡判斷示例介紹,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
Android 判斷SIM卡是中國移動\中國聯(lián)通\中國電信(移動運營商)
本文給帶來兩種方法來判斷sim卡是屬于哪個運營商的,要實現(xiàn)此功能我們需要先獲取手機的imsi碼然后在判斷,對此功能感興趣的朋友一起通過本文學習吧2016-09-09
Kotlin之自定義 Live Templates詳解(模板代碼)
這篇文章主要介紹了Kotlin之自定義 Live Templates詳解(模板代碼),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03

