Android 檢視高度和陰影的那點事兒

亦楓發表於2019-03-01

Material Design 規範針對 UI 元素提出了“高度”這一概念,使過去流行於擬物化設計中的陰影效果,在扁平化設計中消失了很久之後,再次顯現。不過,雖然檢視高度更多的是以陰影的形式直觀地表現在介面中,但更多地是強調一個元素相對重要性的問題。在三維空間中,擁有更高高度的 UI 元素,顯然對於使用者來講,相比於其他元素,更加凸顯其重要性,更加希望被使用者注意到,甚至被頻繁操作,這也是設計人員最想表達的初衷。

Android 中的檢視高度: Z 屬性


瞭解三維空間中的 Z 屬性,引用官網的一段介紹:

由 Z 屬性所表示的檢視高度將決定其陰影的視覺外觀:擁有較高 Z 值的檢視將投射更大且更柔和的陰影。 擁有較高 Z 值的檢視將擋住擁有較低 Z 值的檢視;不過檢視的 Z 值並不影響檢視的大小。

陰影是由提升的檢視的父項所繪製,因此將受到標準檢視裁剪的影響,而在預設情況下裁剪將由父項執行。

具體體現在 API 上,請看這一表示式:

Z = elevation + translationZ

也就是說,檢視高度由 elevation 和 translationZ 屬性決定:

  • elevation:高度,靜態元件,用於提升 UI 元素高度的屬性;
  • translationZ:Z 值轉換,動態元件,常用於操作 UI 元素時互動動畫的屬性。

不同檢視高度呈現出的陰影效果如圖所示:

Android 檢視高度和陰影的那點事兒
不同檢視高度的陰影

elevation 屬性


UI 控制元件的 elevation 屬性可以設定其高度,呈現在介面中的直觀效果就是陰影效果,在 xml 佈局檔案中,通過 android:elevation 屬性設定,在 java 程式碼中通過 View 類提供的 setElevation() 方法設定。但是這個屬性存在版本相容問題,是 Android 5.0 引進的 API。所以,當 minSdkVersion 值小於21時,系統會在 xml 的對應使用地方給出一個 lint 提示:

Attribute elevation is only used in API level 21 and higher

當然你也可以選擇忽略這個提示,或者使用 tools:targetApi 屬性消除這個提示,這樣做的話,在低於 5.0 版本的系統中將不會出現陰影效果。然而,有一個更好的辦法做到相容,那就是藉助 ViewCompat 這個萬能的相容類,使 View 的 elevation 屬性相容至低版本中:

ViewCompat.setElevation(View view, float elevation)

注意:尤其要注意,檢視的陰影一定是由有輪廓的檢視投射出來的。簡單來說,就是需要設定控制元件的背景,即 android:background 屬性。我們可以選擇圖片作為背景,也可以使用 <shape> 標籤定義一個 drawable 形狀,事實上,後者更為常用。

translationZ 屬性


前面提到,elevation 偏向於一個高度上的靜態提升屬性,而 translationZ 偏向於一個高度上的動態轉換屬性,可用於設定動畫,比如元素觸控狀態的轉換效果,如果你瞭解 CardView 的設計規範的話,一定了解這個概念,之前我也寫過相關的文章,呈現效果不妨參考:Android 使用CardView輕鬆實現卡片式設計

我們可以通過屬性動畫動態改變 translationZ 屬性值,為檢視新增高度動畫,也可以在 drawable 目錄下定義一個資原始檔,然後通過 android:stateListAnimator="@drawable/selector_elevation" 屬性顯式地設定給相應的 View 控制元件。其中,selector_elevation 檔案可以這樣定義(名字可以自由編寫):

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:state_pressed="true">
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="@dimen/dp_4"
            android:valueType="floatType" />
    </item>
    <item>
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="0dp"
            android:valueType="floatType" />
    </item>
</selector>複製程式碼

實現陰影的其他方式


可以看出,通過設定檢視高度可以實現陰影效果。這裡需要提及一點,不要與 TextView 控制元件的 shadow 相關屬性混為一談,後者實現的是內容文字的投影效果,具體由 shadowColor、shadowRadius、shadowDx、shadowDy 四個屬性控制,與本文中介紹的檢視陰影概念大相徑庭。

像 support:design 包中的 FloatingActionBar、CardView 控制元件預設都實現了高度上的陰影效果。需要注意的是,前面我們提到的陰影效果都是由於檢視 Z 屬性提升帶來的結果,形狀由檢視的輪廓所決定的,比如圓形、方形等,至於陰影顏色,所有 UI 元素都是一致的,是無法改變的。

那麼還有沒有其他方式實現呢,如果我想改變陰影顏色呢,或者只是區域性投影呢?答案是肯定的,那就是使用帶陰影的背景圖,常見如 .9 圖。比如,系統就給我們提供了一個帶陰影效果的 .9 背景圖,你可以這樣使用:

android:background="@android:drawable/dialog_holo_light_frame"複製程式碼

或者你也可以通過 <layer-list> 標籤去一層一層定義形狀和顏色,不過比較繁瑣,不如直接使用 .9 背景圖片。這裡給大家推薦一個線上工具,通過 GUI 方式製作 .9 陰影背景圖,Android 9-patch shadow generator,如圖:

Android 檢視高度和陰影的那點事兒
Android 9-patch shadow generator

再或者,你可以嘗試一下 GitHub 上的這個開源庫,借鑑一下作者的思路,更靈活地實現 Android App 中的 UI 陰影效果:

github.com/dmytrodanyl…

歡迎關注我


本文由 亦楓 創作並首發於 亦楓的個人部落格 ,同步授權微信公眾號:技術鳥(NiaoTech),歡迎關注。

Android 檢視高度和陰影的那點事兒

相關文章