Material Design 實戰 之第三彈—— 懸浮按鈕和可互動提示(FloatingActionButton & Snackbar & Coo...
本模組共有六篇文章,參考郭神的《第一行程式碼》,對Material Design的學習做一個詳細的筆記,大家可以一起交流一下:
- ofollow,noindex">Material Design 實戰 之第一彈——Toolbar(即本文)
- Material Design 實戰 之第二彈——滑動選單詳解&實戰
- Material Design 實戰 之第三彈—— 懸浮按鈕和可互動提示(FloatingActionButton & Snackbar & CoordinatorLayout)
- Material Design 實戰 之第四彈 —— 卡片佈局以及靈動的標題欄(CardView & AppBarLayout)
- Material Design 實戰 之第五彈 —— 下拉重新整理(SwipeRefreshLayout)
- Material Design 實戰 之 第六彈 —— 可摺疊式標題欄(CollapsingToolbarLayout) & 系統差異型的功能實現(充分利用系統狀態列空間)
立面設計是Material Design中一條非常重要的設計思想,也就是說,按照Material Design的理念,應用程式的介面不僅僅只是一個平面,而應該是有 立體效果 的。
在官方給出的示例中,最簡單且最具代表性的立面設計就是 懸浮按鈕 了,這種按鈕不屬於主介面平面的一部分,而是位於另外一個維度的,因此就會給人一種懸浮的感覺。
以及,本文繼續記錄除了Toas的另外一種可互動式的提示工具。
文章提要與總結
1. FloatingActionButton 1.1. 佈局:主要關注layout_gravity,其他屬性沒有什麼特別的; 1.2. FloatingActionButton的點選事件: 1.2.1 例項化 1.2.2 例項化的 FloatingActionButton物件呼叫setOnClickListener方法註冊監聽,類似Button 2. Snackbar 2.1 呼叫了Snackbar的make()方法來建立一個Snackbar物件 (注意三個引數含義:view,"text", Snackbar.LENGTH_SHORT); 2.2 Snackbar的make()後面連綴呼叫setAction()來設定一個動作 (兩個引數:一參為bar欄右側點選互動顯示內容,二參為重寫onClick()的OnClickListener()物件) 3. CoordinatorLayout 3.1 CoordinatorLayout可以說是一個加強版的FrameLayout,這個佈局也是由DesignSupport庫 提供的; 3.2 CoordinatorLayout可以監聽其所有子控制元件的各種事件,然後自動幫助我們做出最為合理的響應; 3.3 如果我們能讓CoordinatorLayout監聽到Snackbar的彈出事件, 那麼它會自動將內部的FloatingActionButton向上偏移,從而確保不會被Snackbar遮擋到。 3.4 使用:當成FrameLayout使用即可,替換FrameLayout原來的位置.
FloatingActionButton
- FloatingActionButton是DesignSupport庫中提供的一個控制元件,這個控制元件可以幫助我們比較輕鬆地實現懸浮按鈕的效果。
- 它預設會使用colorAccent來作為按鈕的顏色,
- 我們還可以通過給按鈕指定一個圖示來表明這個按鈕的作用是什麼。
下面開始來具體實現。首先仍然需要提前準備好一個圖示,這裡放置了一張ic_done.png到drawable-xxhdpi目錄下。然後修改activity-mam.xml中的程式碼,如下所示:

<android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="16dp" android:src="@drawable/ic_done"/>
可見這裡在主屏幕布局中加人了一個FloatingAcUonButton。
layout_width和layout_height屬性都指定成wrap_content;
layout-gravity屬性指定將這個控制元件放置於螢幕的右下角,
其中end的工作原理和之前的start是一樣的,即如果系統語言是從左往右的,那麼end就表示在右邊,如果系統語言是從右往左的,那麼end就表示在左邊;
layout-margin屬性給控制元件四周留邊距,緊貼著螢幕邊緣不好看;
最後src屬性給FloatingActionButton設定了一個圖示。
執行效果圖:

一個漂亮的懸浮按鈕就出現在螢幕右下角了:



下面實戰懸浮按鈕的點選事件:
在MainActivity的onCreate()中新增以下程式碼:
//懸浮按鈕點選事件 FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "FAB clickes", Toast.LENGTH_SHORT).show(); } });

執行程式,效果如圖:

Snackbar

- 首先要明確,Snackbar並不是Toast的替代品,它們兩者之間有著不同的應用場景。
- Toast 的作用是告訴使用者現在發生了什麼事情,但同時 使用者只能被動接收 這個事情,因為沒有什麼辦法能讓使用者進行選擇。
- 而 Snackba r則在這方面進行了擴充套件, 它允許在提示當中加人一個可互動按鈕 , 當用戶點選按鈕的時候可以執行一些額外的邏輯操作 。
- 打個比方,如果我們在執行刪除操作的時候只彈出一個Toast提示,那麼使用者要是誤刪了某個重要資料的話肯定會十分抓狂吧,但是如果我們增加一個 Undo 按鈕,就相當於給使用者提供了一種 彌補措施 ,從而大大降低了事故發生的概率,提升了使用者體驗。
可以看到,這裡呼叫了Snackbar的make()方法來建立一個Snackbar物件,
make()方法的
- 第一個引數需要傳人一個View,只要是當前介面佈局的任意一個View都可以,Snackbar會使用
這個View來自動查詢最外層的佈局,用於展示Snackbar。 - 第二個引數就是Snackbar中顯示的內容,
- 第三個引數是Snackbar顯示的時長。
這些和Toast都是類似的。接著這裡又呼叫了一個setAction()方法來設定一個動作,從而讓Snackbar不僅僅是一個提示,而是可以和使用者進行互動的。
簡單起見,我們在動作按鈕的點選事件裡面彈出一個Toast提示。
最後呼叫show()方法讓Snackbar顯示出來。
//懸浮按鈕點選事件 FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Toast.makeText(MainActivity.this, "FAB clickes", Toast.LENGTH_SHORT).show(); //Snackbar Snackbar.make(v,"Data deleted", Snackbar.LENGTH_SHORT) .setAction("Undo", new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Data restored", Toast.LENGTH_SHORT).show(); } }).show(); } });
現在重新執行一下程式,並點選懸浮按鈕,效果如圖所示:

可以看到,Snackbar從螢幕底部出現了,上面有我們所設定的提示文字,還有一個Undo按鈕,按鈕是可以點選的。

過一段時間後Snackbar會自動從螢幕底部消失。
不管是出現還是消失,Snackbar都是帶有動畫效果的,因此視覺體驗也會比較好。
不過你有沒有發現一個bug,這個Snackbar竟然將我們的懸浮按鈕給遮擋住了。雖說也不是
什麼重大的問題,因為Snackbar過一會兒就會自動消失,但這種使用者體驗總歸是不友好的。有
沒有什麼辦法能解決一下呢?當然有,只需要藉助 CoordinatorLayout
就可以輕鬆解決。
CoordinatorLayout
CoordinatorLayout可以說是一個加強版的FrameLayout,這個佈局也是由DesignSupport庫
Coordinator n.協調者
它在普通情況下的作用和FrameLayout基本一致,
不過既然是DesignSupport庫中提供的佈局,那麼就必然有一些MaterialDesign的魔力了。
事實上,CoordinatorLayout可以監聽其所有子控制元件的各種事件,然後自動幫助我們做出最為合理的響應。
舉個簡單的例子,剛才彈出的Snackbar提示將懸浮按鈕遮擋住了,
而如果我們能讓CoordinatorLayout監聽到Snackbar的彈出事件,
至於CoordmatorLayout的使用也非常簡單,我們只需要 將原來的FrameLayout替換一下就可以了。
修改activity_mam.xml中的程式碼,如下所示:

<android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="16dp" android:src="@drawable/ic_done" app:elevation="8dp"/> </android.support.design.widget.CoordinatorLayout>
由於CoordinatorLayout本身就是一個加強版的FrameLayout,因此這種替換不會有任何的副作用。
現在重新執行一下程式,並點選懸浮按鈕,效果如圖所示:


不過我們回過頭來再思考一下,剛才說的是CoordinatorLayout可以監聽其所有子控制元件的各種事件,但是Snackbar好像並不是CoordinatorLayout的子控制元件吧,為什麼它卻可以被監聽到呢?
其實道理很簡單,還記得我們在Snackbar的make()方法中傳入的第一個引數嗎?
這個引數就是用來指定Snackbar是基於哪個View來觸發的,
剛才我們傳入的是
FloatingActionButton
本身(Snackbar在FloatingActionButton 基礎的onClick中產生,而這個 onCilck(View view)
函式頭攜帶的引數view,即是FloatingActionButton) ,
而FloatingActionButton是CoordinatorLayout中的子控制元件,
因此這個事件就理所應當能被監聽到了。
(Snackbar → FloatingActionButton → CoordinatorLayout)
這裡可以再做個試驗,如果給Snackbar的make()方法傳入一個DrawerLayout,那麼Snackbar就會再次遮擋住懸浮按鈕,因為DrawerLayout不是CoordinatorLayout的子控制元件,CoordinatorLayout也就無法監聽到Snackbar的彈出和隱藏事件了。
本節的內容就到這裡,接下來我們繼續豐富MaterialTest專案,加人卡片式佈局效果。