更多Material Design 文章請看:
Material Design 之 Toolbar 開發實踐總結
Material Design之 AppbarLayout 開發實踐總結
Material Design 之 Behavior的使用和自定義Behavior
Material Design 之 TabLayout 使用
Material Design 之 TextInputLayout和TextInputEditText
這是Material Design 系列的最後一篇文章,前面幾篇文章講了Material Design中一些比較重要而且經常使用的控件,最後這一篇文章算是一個補充,講一下CardView、FloatActionButton 和 Snackbar。因爲用法比較簡單,因此就不每個都拎出來單講。如下分別是這三個控件的用法。html
卡片是一張帶有材料屬性的紙片,用做展現更多詳細信息的入口點。卡片包含了一組特定的數據集,數據集含有各類相關信息,如主題照片、文本,連接等等。卡片有固定的寬度和可變的高度。最大高度限制於可適應平臺上單一視圖的內容,但若是須要它能夠臨時擴展(例如,顯示評論欄)。卡片不會翻轉以展現其背後的信息。java
卡片集是共面的,或者統一平面的多張卡片佈局。以下:android
一張卡片包含了一組特定的數據集,考慮在如下這些狀況使用卡片:git
做爲一個集合,比較多種數據類型,好比:圖片、視頻和文本。github
不須要直接比較(如:用戶不會直接比較圖片和文本)app
支持內容高度可變,好比評論。ide
包含響應按鈕,好比+1 按鈕或者評論oop
要使用網格列表,但須要顯示更多文原本補充圖片佈局
以上就是使用卡片的一些場景,看一個使用不當的例子(圖片來自官網):ui
錯誤示例: 這種卡片的使用分散了用戶的注意力,不能快速瀏覽,也不能忽略掉,因此將這些內容放在不一樣的卡片上是難以理解的。其實國內有些知名APP也沒有按照規範來作,給咱們作了錯誤的示範,如知乎日報首頁:
正確的用法以下:
正確示例:可快速瀏覽的列表,用來代替卡片,是表現沒有許多操做的同類內容的合適方法。
以上就是Material Design 設計規範裏給的使用卡片的一些場景和正確使用方法,更多的設計規範請看:Material Design 官網。
咱們要怎麼實現卡片設計呢?Google 給咱們提供了CardView,而且是像下兼容的(L 如下仍然能夠用)。CardView 的用法比較簡單,重要的屬性也就幾個。其實用CardView主要實現的圓角和陰影效果。看一下CardView的屬性:
app:cardBackgroundColor 設置卡片的背景色
app:cardCornerRadius 設置卡片的圓角
app:cardElevation 設置卡片的陰影
app:cardUseCompatPadding 是否添加padding
app:cardPreventCornerOverlap 在v20和v20之前的版本添加padding,防止CardView的內容和圓角相交
上面幾個屬性是CardView的幾個經常使用的屬性,固然也能夠在代碼中設置,調用CardView.setXXX就行
mCardView = (CardView) findViewById(R.id.card_view);
//設置背景
mCardView.setCardBackgroundColor(getColor(R.color.colorPrimary));
//設置圓角
mCardView.setRadius(5);
//設置陰影
mCardView.setCardElevation(3);
//設置 兼容padding
mCardView.setUseCompatPadding(true);
//
mCardView.setPreventCornerOverlap(true);複製代碼
比較簡單,就上面幾個屬性,都一一介紹了,看一些示例:
<?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"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="3dp"
app:cardElevation="3dp"
app:cardUseCompatPadding="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/meizhi"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="Material Design"
android:textColor="@color/black"
android:layout_marginTop="16dp"
android:paddingRight="16dp"
android:paddingLeft="16dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginTop="6dp"
android:paddingRight="16dp"
android:paddingLeft="16dp"
android:text=" material metaphor is the unifying theory of a rationalized space and a system of motion."
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16sp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/orange"
android:textSize="24sp"
android:text="SHARE"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/orange"
android:textSize="24sp"
android:text="EXPLORE"
android:layout_marginLeft="20dp"
/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="100dp"
app:cardBackgroundColor="@color/DarkCyan"
app:cardUseCompatPadding="true"
app:cardElevation="4dp"
app:cardCornerRadius="5dp"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Card"
android:textColor="@color/white"
android:textSize="20sp"
android:gravity="center"
/>
</android.support.v7.widget.CardView>
</LinearLayout>複製代碼
效果以下:
CardView 點擊效果
Material Design 的設計就是爲了更貼近現實生活中的場景,當點擊以後,是會有反饋的,能夠給CardView 添加點擊效果。
android:clickable="true"
android:foreground="?attr/selectableItemBackground"複製代碼
這樣點擊時就會有波紋擴散效果了,增長體驗。
FloatingActionButton(浮動操做按鈕,如下簡稱FAB)適用於特定的進階操做。它是漂浮在 UI 上的一個圓形圖標,具備一些動態的效果,好比變形、彈出、位移等等。FAB有3種尺寸,默認尺寸、mini 尺寸和 auto 尺寸 。
默認尺寸:適用於大多數狀況
mini 尺寸:僅用於建立與其餘屏幕元素視覺的連續性。
auto: 基於Window(窗口)大小變化的,當窗口大小小於470dp,會選擇一個較小尺寸的button,更大一點的窗口就選擇更大的button
能夠經過 fabSize 來控制FAB的size。由於FAB這個類繼承自ImageView,因此咱們能夠經過setImageDrawable() 方法來控制FAB icon 的顯示。FAB 默認的背景色是colorAccent,若是你想在運行時改變它的顏色,你能夠調用方法setBackgroundTintList(ColorStateList)) 來改變。
介紹一下FAB的幾個屬性:
app:rippleColor 擴散效果的顏色
app:fabSize 設置 FAB 的 size
app:layout_anchor 設置錨點
app:useCompatPadding 兼容padding 可用
屬性比較簡單,前面講Behavior 的時候提到過,FAB 和 AppbarLayout 的聯動和FAB和Snackbar的Behavior 確保Snackbar 從底部彈出時,不會遮擋FAB,而會相應的上移。這2個也是FAB 經常使用的場景,效果以下:
佈局以下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@drawable/meizhi"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
/>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="18dp"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_dialog_email"
android:layout_marginBottom="20dp"
android:layout_marginRight="15dp"
android:layout_gravity="bottom|right"
app:rippleColor="@android:color/darker_gray"
app:elevation="3dp"
/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_book_list"
android:layout_marginBottom="20dp"
android:layout_marginRight="15dp"
app:layout_anchor="@+id/appbar_layout"
app:layout_anchorGravity="bottom|right"
app:elevation="5dp"
/>
</android.support.design.widget.CoordinatorLayout>複製代碼
代碼中改變FAB 顏色,icon等:
fab1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(fab1,"點擊fab1",Snackbar.LENGTH_LONG).show();
}
});
fab1.setBackgroundTintList(ColorStateList.valueOf(getResources().getColor(R.color.colorPrimary)));
fab2.setImageResource(R.drawable.ic_book_list);
fab2.setCompatElevation(6);
fab2.setSize(FloatingActionButton.SIZE_NORMAL);複製代碼
還能夠監聽FAB的隱藏或者顯示,在項目中可能會有這樣的需求,當FAB隱藏或者顯示以後,接下來作什麼操做,監聽代碼以下:
fab2.hide(new FloatingActionButton.OnVisibilityChangedListener() {
@Override
public void onHidden(FloatingActionButton fab) {
Log.i(TAG,"fab hidden...");
}
});
fab2.show(new FloatingActionButton.OnVisibilityChangedListener() {
@Override
public void onShown(FloatingActionButton fab) {
Log.i(TAG,"fab show...");
}
});複製代碼
能夠在對應的回調方法裏作接下來的操做。
Snackbar 是一種針對操做的輕量級反饋機制,常以一個小的彈出框的形式,出如今手機屏幕下方或者桌面左下方。它們出如今屏幕全部層的最上方,包括浮動操做按鈕。
它們會在超時或者用戶在屏幕其餘地方觸摸以後自動消失。Snackbar 能夠在屏幕上滑動關閉。當它們出現時,不會阻礙用戶在屏幕上的輸入,而且也不支持輸入。屏幕上同時最多隻能現實一個 Snackbar。
Android 也提供了一種主要用於提示系統消息的膠囊狀的提示框 Toast。Toast 同 Snackbar 很是類似,可是 Toast 並不包含操做也不能從屏幕上滑動關閉。
用法:
Snackbar的高度應該能容納下所提示的 文本,而且提示與操做相關,因此不該該提示長文本,Snackbar的用法與Toast很是類似。
彈出一個Toast 的代碼:
Toast.makeText(FABSimpleActivity.this,"哈哈,我是Toast",Toast.LENGTH_SHORT).show();複製代碼
彈出一個snackbar的代碼:
fab2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(fab2,"哈哈,我是Snackbar",Snackbar.LENGTH_SHORT).show();
}
});複製代碼
效果以下:
從上面的代碼能夠看出,Toast與Snackbar的調用方法很是類似,第一個參數有點區別,Toast的第一個參數是一個Context,Snackbar的第一個參數是View,但其實都是異曲同工的,Snackbar也是根據傳入的View找到一個Parent View ,而後再獲取Context。或許大家跟我同樣很奇怪爲何要繞着麼大一圈來獲取這個Context,像Toast 同樣直接傳一個Context不行嗎?答案是不行的,由於須要告訴Snackbar,讓它顯示在哪一個容器內。Snackbar 和Toast的方式不同,看一下源碼一目瞭然,走讀一下源碼:
1,在make方法裏構造了Snackbar,傳入的參數是根據傳的View找到的Parent View :
public static Snackbar make(@NonNull View view, @NonNull CharSequence text, @Duration int duration) {
Snackbar snackbar = new Snackbar(findSuitableParent(view));
snackbar.setText(text);
snackbar.setDuration(duration);
return snackbar;
}複製代碼
Snackbar 構造方法:
private Snackbar(ViewGroup parent) {
mTargetParent = parent;
mContext = parent.getContext();
ThemeUtils.checkAppCompatTheme(mContext);
LayoutInflater inflater = LayoutInflater.from(mContext);
mView = (SnackbarLayout) inflater.inflate(
R.layout.design_layout_snackbar, mTargetParent, false);
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
}複製代碼
上面inflate 的時候用到了mTargetParent,告訴Snackbar要顯示在哪一個容器內。
再看一下show 的方式:
public void show() {
SnackbarManager.getInstance().show(mDuration, mManagerCallback);
}複製代碼
而後調用scheduleTimeoutLocked 方法:
private void scheduleTimeoutLocked(SnackbarRecord r) {
if (r.duration == Snackbar.LENGTH_INDEFINITE) {
// If we're set to indefinite, we don't want to set a timeout
return;
}
int durationMs = LONG_DURATION_MS;
if (r.duration > 0) {
durationMs = r.duration;
} else if (r.duration == Snackbar.LENGTH_SHORT) {
durationMs = SHORT_DURATION_MS;
}
mHandler.removeCallbacksAndMessages(r);
mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_TIMEOUT, r), durationMs);
}複製代碼
最後是用Handler 發了一條消息,通知顯示:
static {
sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case MSG_SHOW:
((Snackbar) message.obj).showView();
return true;
case MSG_DISMISS:
((Snackbar) message.obj).hideView(message.arg1);
return true;
}
return false;
}
});
}複製代碼
看到這兒大概就明白了,最終調用的是showView()這個方法顯示:
final void showView() {
...
// 上面省略的部分主要是判斷是否是CoordinatorLayout的子View,若是添加Behavior
if (ViewCompat.isLaidOut(mView)) {
if (shouldAnimate()) {
// If animations are enabled, animate it in
animateViewIn();
} else {
// Else if anims are disabled just call back now
onViewShown();
}
} else {
// Otherwise, add one of our layout change listeners and show it in when laid out
mView.setOnLayoutChangeListener(new SnackbarLayout.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view, int left, int top, int right, int bottom) {
mView.setOnLayoutChangeListener(null);
if (shouldAnimate()) {
// If animations are enabled, animate it in
animateViewIn();
} else {
// Else if anims are disabled just call back now
onViewShown();
}
}
});
}
}複製代碼
以上分析了Snackbar 的建立顯示過程。其實使用是很簡單的,跟之前使用Toast提示差很少。
最後還有一點就是,Toast只能給個提示,而Snackbar咱們還能夠給他設置一個Action,當顯示Snackbar的時候,咱們點擊Action按鈕,執行相應的操做
代碼:
private void showSnackbar(){
Snackbar snackbar = Snackbar.make(fab2,"哈哈,我是Snackbar",Snackbar.LENGTH_SHORT);
snackbar.setAction("UNDO", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(FABSimpleActivity.this,"執行Undo操做",Toast.LENGTH_LONG).show();
}
});
snackbar.setActionTextColor(getResources().getColor(R.color.DarkCyan));
snackbar.setText("已經刪除1張照片");
snackbar.show();
}複製代碼
效果以下:
如上圖所示,添加了一個UNDO 按鈕,點擊按鈕之行相應操做。
這個三個控件的用法比較簡單,本文從它們的使用場景和原理講了它們的基本用法,瞭解這些以後,能夠加深印象。本文是Material Design 相關的最後一篇文章,可能還有一些零碎的東西沒有講到,還有一些像RecyclerView 這些的用法網上的博客已經不少了,有的也寫得很好很詳細,不打算再寫。另外,Material Design 系列的Demo在這兒:MaterialDesignSamples