Android開發技巧之xml tools屬性詳解
我們知道,在 Android 開發過程中,我們的資料常常來自於服務端,只有在執行時才能獲得資料展示,因此在佈局 XML 的編寫過程中,由於缺少資料,我們很難直接看到填充資料後的佈局效果,那這個時候你一般是怎麼做的呢?
經常看到一些小夥伴的做法是在佈局檔案中臨時寫死一些資料來檢視佈局展示效果,在檢視結束後,再手動將這些資料進行刪除。
是不是很麻煩,那我們有沒有更簡單點的方案呢?
針對上述的問題,Google 官方其實早就考慮到了,因此在開發工具中提供了 tools 名稱空間的支援。
在佈局 XML 檔案中使用
tools:
名稱空間新增的屬性,在專案構建成 過程中,tools 屬性會被構建工具自動移除,最終不會對構建程式產生任何的影響。
而除去在編寫佈局時的預覽功能外,tools:
名稱空間屬性還提供了很多有用的功能,那麼接下來我們就來詳細介紹下 tools 屬性的這些功能。
按照官方的定義, tools 屬性劃分為了三種類型:
錯誤控制屬性(Error handling attributes)
主要用來幫助我們控制一些由 lint 產生的錯誤警告。
tools:ignore
適合於任意元素
我們知道,在 Android 開發工具中提供了 lint 工具,可以幫助您輕鬆地識別並糾正問題與結構質量的程式碼。
而 lint 中針對不同的問題警告定義了不同的 ID,該屬性則可以通過設定 lint 中對應的問題 ID 來讓 lint 忽略該種警告,同時也可以通過逗號分隔符的方式設定多個問題 ID 來忽略多種警告。
例:
<string name="show_all_apps" tools:ignore="MissingTranslation">All</string>
一般在存在多國語言資源包的情況下, 如果 strings.xml 裡某個String 沒有給出其他語言版本的翻譯, 那麼 lint 會給出 MissingTranslation 的警告提示,
而通過 tools:ignore="MissingTranslation"
我們就可以讓 Lint 針對這條 String 忽略這個警告。
再例如我們開發中更常見的一個問題:
在使用 ImageView 標籤時,如果不加 android:contentDescription
此時,我們可以通過給 ImageView 標籤新增 tools:ignore="contentDescription"
來忽略這個警告。
<ImageView ...
tools:ignore="contentDescription"
/>
tools:targetApi
適用於任何元素
這個屬性類似我們在程式碼中使用 @TargetApi
註解
當我們使用的元件元素支援的 Android 最低版本大於我們專案所指定的最低版本 minSdkVersion 時, lint 會給出相應的版本警告。
該屬性則可以通過給指定的佈局設定對應的 API 版本來通知 lint 忽略警告。
例:
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="14" >
如果我們不使用 v4 包下的 GridLayout , 那麼 GridLayout 則只支援 API LEVEL 14 以上系統,此時如果我們專案的 minSdkVersion 低於14 ,那麼 lint 會給出版本警告
當添加了 tools:targetApi="14"
之後,Lint 就會停止對應的版本警告了。
tools:locale
適用於 <resources>
元素
這個屬性用來指定預設的資原始檔所使用的語言環境,從而避免 Lint 在拼寫檢測的時候帶來不必要的警告提示。
預設情況下,開發工具會假設我們的語言環境為英語,因此單詞檢測器(spell checker)在檢測過程中會對一些英文字母產生警告。
例如,我的 app_name 叫TRSDK, 預設情況下 TRSDK 下會產生波浪線的警告提示:
此時如果我通過 tools:locale
設定預設環境為中文 zh,那麼警告就會消失了
設計時預覽屬性(Design-time view attributes)
這類屬性主要是針對於 Android layout 佈局的特徵屬性的,通過設定這類屬性可以在 Android Studio 的佈局預覽介面快速預覽佈局展示效果。
tools: instead of android:(可替代任何 android:
開頭的屬性)
適用於 <view>
類檢視元素
你可以針對檢視元件的屬性,通過使用 tools :
字首來替換 android:
字首,從而提前在佈局預覽介面預覽屬性設定的效果。
並且在程式碼構建的時候,構建工具會自動移除這些屬性,不對最終打包的 APK 產生任何影響。
例如:
如果 TextView 的資料需要在執行時才能獲取,那我們可以通過設定 tool:text
的值,在佈局預覽介面預覽資料填充後的效果,如圖:
我們可以同時設定 android: 屬性(執行時才能顯示) 和匹配的 tools: 屬性(只會在佈局預覽介面顯示),構建專案時最終 tools 屬性會被移除,只以 android: 屬性的值顯示。
假設 FrameLyout 中有多個子佈局,並且我們只想預覽有一個佈局時的效果,此時,我們也可以通過設定 tools 屬性來預覽一個子佈局時的顯示效果:
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="First" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Second"
tools:visibility="invisible" />
tools:context
適用於部分 <view>
根佈局
該屬性用於設定佈局檔案相關的 Activity,從而使用開發工具的快速修復功能( quick fix )時能自動關聯 Activity 上下文生成對應的程式碼。
例如:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:text="Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_weight="1"
android:onClick="onButtonClicked"/>
</LinearLayout>
這裡我們給根佈局 LinearLayout 設定了 tools:context = “.MainActivity”,當我們使用 Android Studio 的快速修復功能時,則會關聯相關的 Activity 進行提示:
tools:layout
適用於 <fragment>
該屬性用來定義需要在 fragment 內進行繪製的佈局 layout ,從而在佈局預覽介面預覽 fragment 的顯示檢視。
例如:
<fragment android:name="com.example.master.ItemListFragment"
tools:layout="@layout/list_content" />
tools:listitem / tools:listheader / tools:listfooter
適用於 <AdapterView>
還有 <ListView>
的子類
我們知道,在編寫列表的時候,列表的 item 佈局都是在 adapter 的 getView 裡通過程式碼來進行設定的,在非執行時的環境下,無法看到列表的直接預覽效果。
這幾個屬性便提供了這樣的功能,通過直接設定對應的 layout 佈局,我們可以在開發工具的佈局預覽介面直接看到顯示效果:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/sample_list_item"
tools:listheader="@layout/sample_list_header"
tools:listfooter="@layout/sample_list_footer" />
tools:showIn
適用於被 <include>
標籤引用的佈局根 <view>
假設 TextView 在 activity_main 佈局中被 引用了,此時如果通過 tools:showIn 指向 activity_main, 則此時在佈局預覽介面能看到 TextView 在 activity_main 中的顯示效果。
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:showIn="@layout/activity_main" />
tools:menu
適用於部分根 <view>
這個屬性用來指定需要在 app bar 中顯示的 menu 佈局,可以使用逗號分隔符來指定多個 menu 佈局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:menu="menu1,menu2" />
不過目前在 toolbar 下測試並未有效,如果有小夥伴知道該屬性具體如何使用的,歡迎在評論中留言哈。
資源篩減屬性(Resource shrinking attributes)
該型別屬性允許你啟用嚴格關聯檢測
並且決定在專案構建的時候是否保留或丟棄指定的資原始檔。
使用該屬性需要在 build.gradle 中設定 shinkResources 為 true 來開啟資源壓縮功能。
開啟資源壓縮後,在程式碼中或資原始檔中未被引用的資源會在構建過程中被移除。
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
tools:shrinkMode
適用於 <resources>
資源標籤
該屬性允許你指定構建工具是否使用 “safe mode” 安全模式 (該模式會保留所有明確引用的資源以及可能被 Resources.getIdentifier()
動態引用的資源)
或是 “strict mode” 嚴格模式 (該模式只保留在程式碼或者資原始檔中明確引用的資源)
預設情況下 shrinkMode=”safe”,如果需要使用嚴格模式,則在 中設定 tools:shrinkMode=”strict”
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:shrinkMode="strict" />
tools:keep
適用於 <resources>
資源標籤
當開啟了資源壓縮(shrinking resource)功能時,這個屬性允許你指定哪些資源需要被保留。
因為開啟了資源壓縮功能後,未被引用的資原始檔會在構建過程中被移除,而部分使用 Resources.getIdentifier()
進行引用的資原始檔可能被誤刪。
此時我們可以使用該屬性指定哪些資源需要保留,不能被移除:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/used_1,@layout/used_2,@layout/*_3" />
tools:discard
適用於 <resources>
資源標籤
當使用資源壓縮功能移除沒用的資原始檔時,有些資源雖然被引用了,但移除對 app 不會產生任何影響,或者因為 Gradle plugin 錯誤地移除了關聯的資源。
此時,我們可以通過這個屬性來指定需要移除的資源:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:discard="@layout/unused_1" />