Material design中有一種很個性的設計概念:卡片式設計(Cards),這種設計與傳統的List Item有所區別,Cards包含更多的內容元素和擁有本身的UI特徵,關於Cards的設計規範能夠參考官網介紹:php
material.google.com/components/…html
爲了更好地實現這種 Cards UI 的設計,Google在v7包中引進了一種全新的控件:CardVew,本文將從開發的角度介紹CardView的一些常見使用細節。java
Google用一句話介紹了CardView:一個帶圓角和陰影背景的FrameLayout。CardView在Android Lollipop(API 21)及以上版本的系統中適配較好,本文咱們以一個具體的例子來學習CardView的基本使用和注意事項,效果圖以下:android
上圖展現的是一個list列表,列表中的item使用了卡片式設計,主要利用CardView控件實現,爲了精簡文章內容,這裏咱們將item佈局中的核心代碼羅列出來,加以分析:ios
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<android.support.v7.widget.CardView tools:targetApi="lollipop" android:layout_width="match_parent" android:layout_height="wrap_content" android:stateListAnimator="@drawable/lift_on_touch" android:layout_marginLeft="@dimen/dp_8" android:layout_marginRight="@dimen/dp_8" android:layout_marginBottom="@dimen/dp_8" android:clickable="true" android:foreground="?android:attr/selectableItemBackground" app:cardCornerRadius="@dimen/dp_4" app:cardUseCompatPadding="true" app:cardPreventCornerOverlap="false">
<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content">
<!-- image、text等其餘內容 -->
......
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>複製代碼
能夠看出,核心部分在於CardView的屬性使用,下面咱們針對幾個特殊的屬性逐一分析,深化了解。git
前面咱們說過,CardView從本質上屬於FrameLayout,而CardView一般包含了較多的內容元素,爲了方便地排版佈局中的各個元素,通常藉助於其餘基本佈局容器,好比這裏咱們使用了一個RelativeLayout
做爲CardView的惟一Child。程序員
在Android Lollipop以前的系統,CardView會自動添加一些額外的padding空間來繪製陰影部分,這也致使了以Lollipop爲分界線的不一樣系統上CardView的尺寸大小不一樣。爲了解決這個問題,有兩種方法:第一種,使用不一樣API版本的dimension資源適配(也就是藉助values和values-21文件夾中不一樣的dimens.xml文件);第二種,就是使用setUseCompatPadding
屬性,設置爲true(默認值爲false),讓CardView在不一樣系統中使用相同的padding值。github
這也是一個解決系統兼容的問題。在pre-Lollipop平臺(API 21版本以前)上,CardView不會裁剪內容元素以知足圓角需求,而是使用添加padding的替代方案,從而使內容元素不會覆蓋CardView的圓角。而控制這個行爲的屬性就是cardPreventCornerOverlap,默認值爲true。在本例中咱們設置了該屬性爲false。這裏咱們看一下,在pre-Lollipop平臺中,不一樣cardPreventCornerOverlap值的效果對比圖(左false,右true):微信
顯然,默認值下自動添加padding的方式不可取,因此須要設置該屬性值爲false。須要注意的一點是,該屬性的設置在Lollipop及以上版本的系統中沒有任何影響,除非cardUseCompatPadding的值爲true。app
Cards通常都是可點擊的,爲此咱們使用了foreground屬性並使用系統的selectableItemBackground值,同時設置clickable爲true(若是在java代碼中使用了cardView.setOnClickListener,就能夠不用寫clickable屬性了),從而達到在Lollipop及以上版本系統中實現點擊時的漣漪效果(Ripple),如圖:
在pre-Lollipop版本中,則是一個普通的點擊變暗的效果,這裏就不截圖展現了,若是想改變老版本的點擊效果,也能夠經過版本兼容的方式另行修改。
根據官網Material motion部分對交互動做規範的指導,Cards、Button等視圖應該有一個觸摸擡起(lift-on-touch)的交互效果,也就是在三維立體空間上的Z軸發生位移,從而產生一個陰影加深的效果,與Ripple效果共同使用,官網給了一個很好的示例圖:
在實現這個效果也很簡單,能夠在res/drawable
目錄下創建一個lift_on_touch.xml
文件,內容以下:
<?xml version="1.0" encoding="utf-8"?>
<!-- animate the translationZ property of a view when pressed -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:state_pressed="true">
<set>
<objectAnimator android:duration="@android:integer/config_shortAnimTime" android:propertyName="translationZ" android:valueTo="6dp" android:valueType="floatType"/>
</set>
</item>
<item>
<set>
<objectAnimator android:duration="@android:integer/config_shortAnimTime" android:propertyName="translationZ" android:valueTo="0" android:valueType="floatType"/>
</set>
</item>
</selector>複製代碼
即經過屬性動畫動態改變translationZ值,沿着Z軸,從0dp到6dp變化。這裏的6dp值也是有出處的,參考Google I/O 2014 app和Assign Elevation to Your Views。而後將其賦值給android:stateListAnimator
屬性便可。因爲stateListAnimator
屬性只適用於Lollipop及以上版本,爲了隱藏xml中的版本警告,能夠指定tools:targetApi="lollipop"
。
關於這個功能,須要補充說明一點。這裏的lift_on_touch.xml
,嚴格意義上來說,屬於anim資源,同時適用於API 21及以上版本,因此按道理上來說應該將其放置在res/anim-v21
目錄下,而後使用@anim/lift_on_touch
賦值給stateListAnimator
屬性,而不是例子中的@drawable/lift_on_touch
方法。可是放置在res/anim-v21
目錄下會產生一個「錯誤」提示:
XML file should be in either "animator" or "drawable",not "anim"
雖然這個「錯誤」不影響編譯運行,可是對於追求完美主義的程序員們來講仍是礙眼,因此本例中我選擇將其放在了res/drawable
目錄下,你們能夠自行斟酌使用。
關於對lift-on-touch效果的理解,YouToBe網站有個視頻解說,感興趣的話能夠參看看,地址以下:
DesignBytes: Paper and Ink: The Materials that Matter
CardView還有一些其餘屬性可供使用,好比cardElevation
設置陰影大小,contentPadding
代替普通android:padding
屬性等,比較基礎,本文就不一一介紹了,你們能夠在官網上參考學習。從上面的介紹能夠看出,在使用CardView時基本上都會用到一些標準配置的屬性,咱們能夠藉助style屬性,將其封裝到styles.xml
文件中,統一管理,好比:
<style name="AppCardView" parent="@style/CardView.Light"> <item name="cardPreventCornerOverlap">false</item> <item name="cardUseCompatPadding">true</item> <item name="android:foreground">?attr/selectableItemBackground</item> <item name="android:stateListAnimator" tools:targetApi="lollipop">@anim/lift_up</item> ...... </style>複製代碼
最後,附上本文案例項目的GitHub地址:
本文由 亦楓 創做並首發於 亦楓的我的博客 ,同步受權微信公衆號:技術鳥(NiaoTech),歡迎關注。