是時候讓 Android Tools 屬性拯救你了

平常開發過程當中,咱們都會遇到這樣一種場景:咱們寫出的 UI 效果在對接數據以前須要提早進行預覽,進而調整 UI 細節和排版問題。咱們通常的作法是什麼樣的?若是存在像 TextView 或者 ImageView 這種基礎控件,你是否是還在經過諸如 android:text="xxx"android:src="@drawable/xxx" 的方式來測試和預覽UI效果?固然你確定也會遇到這些「髒數據」給你帶來的困擾:測試的時候某些地方出現了本不應出現的數據,過後可能一拍腦門才發現,原來是佈局中控件預覽數據沒有清除致使的。php

若是是 RecyclerView,在後臺接口尚能測試的狀況下,你是否又要本身生成「假數據」並手寫 Adapter 呢?這時候你不由會問:有沒有一種方法,既可以作到佈局時預覽數據方便排版,又可以在對接真實數據運行後動態替換和移除這些無關數據呢?html

鐺鐺鐺鐺!Android 的 Tools attributes 應運而生。老規矩,咱們先來看一個效果:android

What?你在耍我嗎?這麼簡單的列表拿出來幹嗎?哈哈,客觀不要着急。這個並不難實現,假若我說這裏並無寫一行 Java 或者 Kotlin 代碼就實現了此效果,而只是在佈局頁面預覽,你敢信嗎?上圖只是冰山一角,下面這張圖纔是全貌:json

下面會帶你們一步步實現上述功能,首先,讓咱們從頭提及。app

認識 Tools attributes

Tools attributes 即以 tools 開始的命名空間,舉個咱們最多見到的例子:dom

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
    
</android.support.constraint.ConstraintLayout>
複製代碼

你們確定平時都會見到 tools:context=".XXXActivity 這個系統默認爲咱們生成的配置。通常來講,只有根視圖才能使用這個屬性,它指定了當前佈局默認是與哪一個 Activity 相關聯,使得佈局可以獲取到綁定 Activity 的一些信息,好比 Theme 等等,並且當你在佈局中給子 View 添加 onClick 事件時,相應的方法代碼會插入到這個 Activity 中。 Android studio 支持不少在 XML 文件中以 tools 爲命名空間的屬性,當構建 App 時這些屬性會被擦除,對 APK 的大小和運行時行爲沒有任何影響,這也就是咱們文章最初想要的結果。編輯器

細說 Tools attributes

在具體介紹 Tools attributes 以前,咱們須要先了解如何引入 Tools 的命名空間並使用,很簡單,只須要在 XML 佈局文件的根元素中添加便可:ide

<RootTag xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" >
複製代碼

這些工具屬性大概能夠分爲如下三類:工具

Error handling attributes

錯誤和警告處理屬性。這類屬性常被用來規避被 lint 檢查出的一些錯誤提示以及警告。下面讓咱們看一些常見的例子:佈局

  • tools:ignore

    主要用來忽略一些 lint 產生的警告信息,並支持一些屬性,例如:

    <resources xmlns:tools="http://schemas.android.com/tools">
        <string name="app_name">ConstraintSample</string>
        <string name="header_image_string" tools:ignore="MissingTranslation">header image</string>
    </resources>
    複製代碼

    這個對於 Android studio 升級到 3.0 以上的小夥伴來講應該是很常見了,若是咱們項目中涉及到國際化支持,那麼編譯器就會提示咱們爲每一種語言作適配,不能「厚此薄彼」,若是咱們某些 string 只須要支持一種語言,只須要像上面那樣添加 tools:ignore="MissingTranslation 便可。類似的例子還能夠在使用 ImageView 的時候看到:

    <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_person_off" tools:ignore="contentDescription" />
    複製代碼
  • tools:targetApi

    這個屬性的功能和 Java 代碼中的註解 @TargetApi 是同樣的:它指定了當前控件或元素支持的 API 級別,屬性值能夠是 API Code 名或者 API 常數值,它支持一切屬性。如:咱們都知道,android:elevation 屬性是在 API 21 版本以上才支持的,因此咱們能夠經過如下代碼規避 lint 的警告:

    <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:elevation="4dp" tools:targetApi="lollipop"/>
    複製代碼
  • tools:locale

    這個屬性主要用在 <resource> 標籤內,用來指定當前資源中默認爲哪一種語言和區域,進而規避語言拼寫的檢測,好比你能夠指定 values/strings.xml 文件的默認語言是西班牙語而不是英語:

    <resources xmlns:tools="http://schemas.android.com/tools" tools:locale="es">
    複製代碼

Resource shrinking attributes

資源壓縮屬性。關於此類屬性的用法咱們已經在以前的一篇文章帶你領略Android混淆的魅力一文中作過詳細講解,下面再簡單說明一下。

咱們能夠經過 tools:shrinkModetools:keep 屬性來分別指定資源壓縮的模式和須要保留的不被壓縮的資源 ,還能夠經過 tools:discard 屬性來指定須要保留的資源,與 keep 功能相似:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="strict" tools:keep="@layout/activity_video*,@layout/dialog_update_v2" tools:discard="@layout/unused_layout,@drawable/unused_selector" />
複製代碼

下面就到本篇文章的重頭戲了,注意,前方高能來襲!

Design-time View Attributes

這就是咱們先前效果圖中的重要功臣了,即:佈局設計時的控件屬性。這類屬性主要做用於 View 控件,如上文所說的 tools:context 就是「成員」之一,下面咱們來介紹其餘重要成員。

在此以前,咱們須要先揭開 tools 命名空間的另外一層神祕面紗:tools: 能夠替換任何以 android: 爲前綴的屬性,併爲其設置樣例數據sample data)。固然,正如咱們前面所說,tools 屬性只能在佈局編輯期間有效,App真正運行後就毫無心義了,因此,咱們就能夠像下面這樣來在運行前預覽佈局效果

上圖對應的佈局文件爲:

Card_item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:background="@android:color/white" android:clickable="true" android:focusable="true" android:foreground="?attr/selectableItemBackground" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" tools:targetApi="m" tools:ignore="UnusedAttribute">

    <ImageView android:id="@+id/card_item_avatar" android:layout_width="38dp" android:layout_height="38dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="16dp" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp" app:layout_constraintVertical_bias="0.0" tools:ignore="ContentDescription" tools:srcCompat="@drawable/user_other"/>
    <TextView android:id="@+id/card_item_username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="@+id/card_item_title" app:layout_constraintEnd_toEndOf="@+id/card_item_title" app:layout_constraintHorizontal_bias="0.0" android:textSize="12sp" android:textColor="@color/username_text_color" android:layout_marginEnd="16dp" android:paddingEnd="16dp" tools:text="水月沐風" />
    <TextView android:id="@+id/card_item_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp" android:textColor="@color/title_text_color" app:layout_constraintStart_toEndOf="@+id/card_item_avatar" android:layout_marginStart="12dp" app:layout_constraintTop_toBottomOf="@+id/card_item_username" android:layout_marginTop="8dp" android:maxLines="1" tools:text="今天上海的夜色真美!"/>
    <TextView android:id="@+id/card_item_content" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="24dp" app:layout_constraintTop_toBottomOf="@+id/card_item_avatar" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp" app:layout_constraintVertical_bias="1.0" android:maxLines="3" android:ellipsize="end" android:textColor="@color/content_text_color" android:textStyle="normal" app:layout_constraintEnd_toEndOf="@+id/card_item_bottom_border" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" app:layout_constraintHorizontal_bias="0.0" tools:text="人生若只如初見,何事秋風悲畫扇..."/>
    <ImageView android:id="@+id/card_item_poster" android:layout_width="0dp" android:layout_height="200dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/card_item_content" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="16dp" android:scaleType="centerCrop" android:layout_marginTop="8dp" android:layout_marginStart="16dp" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp" app:layout_constraintVertical_bias="0.0" tools:ignore="ContentDescription" android:visibility="visible" tools:src="@drawable/shanghai_night"/>
    <View android:id="@+id/card_item_bottom_border" android:layout_width="0dp" android:layout_height="2dp" app:layout_constraintTop_toBottomOf="@+id/card_item_poster" android:background="#ffededfe" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent"/>
    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/card_item_date" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="16dp" android:textColor="@color/date_text_color" android:textSize="12sp" tools:text="2019-08-10"/>
</android.support.constraint.ConstraintLayout>
複製代碼

經過上面代碼咱們能夠發現:經過 對 TextView 使用 tools:text 屬性代替 android:text 就能夠實現文本具體效果的預覽,然而這項設置並不會對咱們 App 實際運行效果產生影響。同理,經過將 tools:src 做用於 ImageView 也能夠達到預覽圖片的效果。此外。咱們還能夠對其餘以 android: 爲前綴的屬性進行預覽而不影響實際運行的效果,例如:上面佈局代碼中的底部分割線 <View>,咱們想將其在 App 實際運行的時候隱藏掉,但咱們仍是須要知道它的預覽效果和所佔高度:

<View android:id="@+id/card_item_bottom_border" android:layout_width="0dp" android:layout_height="2dp" android:visibility="gone" tools:visibility="visible" tools:layout_height="8dp" app:layout_constraintTop_toBottomOf="@+id/card_item_poster" android:background="#ffededfe" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent"/>
複製代碼

如上所示,經過 tools:visibilitytools:layout_height 就能夠僅在佈局預覽狀況下改變 View 的狀態和高度。雖然上述狀況比較少用,可是但願你們也可以知道,tools: 能夠替代全部 android: 修飾的屬性。

下面再列舉一些其餘會經常使用到的屬性。

  • tools:layout

    這個屬性只能用於 fragment 控件中,若是咱們的 activity 佈局文件中聲明瞭 <fragment> 控件,咱們就能夠經過 tools:layout=」@layout/fragment_main」 來在當前 activity 佈局中預覽 fragment 中的佈局效果。

  • tools:showIn

    這個屬性就比較好玩了,它能夠指定其餘佈局文件像 <include> 組件同樣在當前佈局文件中使用和預覽 <include> 控件的實際效果。例如,咱們 card_item_layout.xml 做爲 showIn 的對象給 show_in_layout.xml 佈局使用,而後我就能夠看到 show_in_layout.xml 中以下效果:

  • tools:menu

    這個屬性能夠給當前佈局預覽器的 Toolbar 添加多個菜單項,但僅限於佈局文件的根節點元素。如:

    <?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" />
    複製代碼
  • tools:maxValue | tools:minValue

    這兩個屬性僅用於 <NumberPicker>,能夠在預覽時指定其最大值和最小值:

    <NumberPicker xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/numberPicker" android:layout_width="match_parent" android:layout_height="wrap_content" tools:minValue="0" tools:maxValue="10" />
    複製代碼
  • tools:listitem | tools:listheader | tools:listfooter | tools:listCount

    下面來說一下列表相關組件的 tools 屬性。上面四個屬性僅用於 <AdapterView> 及其子類(如:ListViewRecyclerView)。然而,它們內部仍有一些使用限制:tools:listCount 僅用於 RecyclerViewtools:listheadertools:listfooter 僅限於 ListView;至於 tools:listitem 屬性兩者皆可用。以前的效果圖就是藉助於此屬性:

    activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:background="#ffEBEBEF">
        <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="0dp" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:theme="?attr/actionBarTheme" android:minHeight="?attr/actionBarSize" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:elevation="1dp" app:title="@string/app_name" app:layout_constraintTop_toTopOf="parent" app:layout_constraintHorizontal_bias="0.0"/>
        <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:scrollbars="vertical" app:layout_constraintTop_toBottomOf="@+id/toolbar" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintVertical_bias="0.0" tools:listitem="@layout/card_item_layout"/>
    </android.support.constraint.ConstraintLayout>
    複製代碼

sample data

樣本數據 功能,能夠經過 @tools:sample 來使用該屬性,也屬於 design-time view attributes。但它並不是只是一個屬性那麼簡單,更應該算是一個「工具利器」,因此會將其單獨拿出來詳細介紹。這個工具是本年度 Google 大會上 Android 開發團隊特別介紹的一個新推屬性。它有什麼用呢?用處大了!先前的佈局預覽使用的數據都是咱們直接在佈局控件中註明或者在 strings.xml 文件中給出的,這一就會產生一些髒數據,不利於咱們後期的處理。而有了 sample data,咱們就能夠對佈局預覽器中的 **「樣本數據」**進行集中保存和管理了。

1、sample data 的使用

Android studio 已爲咱們提供瞭如下樣本數據,我能夠直接拿來使用:

Attribute value Description of placeholder data
@tools:sample/full_names Full names that are randomly generated from the combination of@tools:sample/first_names and @tools:sample/last_names.
@tools:sample/first_names Common first names.
@tools:sample/last_names Common last names.
@tools:sample/cities Names of cities from across the world.
@tools:sample/us_zipcodes Randomly generated US zipcodes.
@tools:sample/us_phones Randomly generated phone numbers with the following format: (800) 555-xxxx.
@tools:sample/lorem Placeholder text that is derived from Latin.
@tools:sample/date/day_of_week Randomized dates and times for the specified format.
@tools:sample/date/ddmmyy
@tools:sample/date/mmddyy
@tools:sample/date/hhmm
@tools:sample/date/hhmmss
@tools:sample/avatars Vector drawables that you can use as profile avatars.
@tools:sample/backgrounds/scenic Images that you can use as backgrounds.

上述表格中不只有經常使用文本數據和日期等數據,還提供了一些圖片樣本數據,那麼該如何使用呢?很簡單,只須要切換到佈局預覽界面,並拖動一個 ImageView 到面板上,而後 Android studio 就會彈出以下界面:

而後選擇 avatars 或者 background/scenic 數據源就能夠了。固然你也能夠經過 xml 代碼形式來設置:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@android:color/white" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent">

    <ImageView android:layout_width="36dp" android:layout_height="36dp" android:id="@+id/imageView" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="16dp" tools:srcCompat="@tools:sample/avatars"/>
    <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/textView" app:layout_constraintStart_toEndOf="@+id/imageView" android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="16dp" app:layout_constraintTop_toTopOf="parent" tools:text="@tools:sample/lorem/random" tools:maxLines="8" android:ellipsize="end" android:textSize="14sp" android:textColor="@color/title_color" android:layout_marginTop="16dp" app:layout_constraintHorizontal_bias="0.0"/>
</android.support.constraint.ConstraintLayout>
複製代碼

一樣地,TextView 也能夠經過 @tools:sample/lorem/random 來添加樣本數據,如此一來,效果以下:

哈哈,還不錯吧😄。那麼問題來了,若是咱們想要用本身的樣本數據源呢?

2、自定義 sample data

若是咱們想要是用本身定製化的樣例數據,該如何作呢?其實很簡單,只須要在 app 目錄下建立 sample data directory 就能夠了:

接下來,咱們就能夠在裏面定製咱們本身的數據了,在剛建好的 sampledata 目錄下新建一個 txt 格式的數據文件,如 users,而後在裏面建立以下數據:

如此這般,同理建立咱們的其餘數據: titlesdescriptions,而後在上述 card_item_layout.xml 佈局文件中替換並使用本身的數據源:

<TextView android:id="@+id/card_item_username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="@+id/card_item_title" app:layout_constraintEnd_toEndOf="@+id/card_item_title" app:layout_constraintHorizontal_bias="0.0" android:textSize="12sp" android:textColor="#8989ae" android:layout_marginEnd="16dp" android:paddingEnd="16dp" tools:text="@sample/users" />
複製代碼

這裏僅以其中一個 TextView 舉例說明,其餘同理。

什麼?你覺得到這裏就講完了?哈哈,少年,看你骨骼驚奇,再教你一招來上天入地:經過自定義 Json 格式的 數據來爲控件綁定數據

打完收工👋,仍是上面的例子,來看看如何經過 json 數據來綁定:

<TextView android:id="@+id/card_item_username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="@+id/card_item_title" app:layout_constraintEnd_toEndOf="@+id/card_item_title" app:layout_constraintHorizontal_bias="0.0" android:textSize="12sp" android:textColor="#8989ae" android:layout_marginEnd="16dp" android:paddingEnd="16dp" tools:text="@sample/sample.json/data/username" />
複製代碼

以上操做的時候 Android studio 都會自動提示 sampledata 路徑下的數據文件,Json 格式亦會提示到具體字段。

最後

從 Google Android 官方的進一步動向來看,後續Android更新過程當中,佈局編輯器將更增強大。從 Tools attributesConstraintLayout1.1 再到即將到來的 ConstraintLayout2.0 中的 MotionLayout,咱們能夠預見:Android 將在 UI 渲染和動畫實現方面進一步解放咱們的雙手。後續我將繼續爲你們帶來系列文章,敬請期待🌈。

相關文章
相關標籤/搜索