Android進階(1)| Material Design

本節目錄
Material Design概述
Material Design是Google在Android 5.0推出的全新的設計語言,它是由Google工程師們基於傳統優秀的設計原則並且結合豐富的創意以及科技所組成的。Material Design的核心思想,就是將物理世界中的體驗帶入螢幕,並且去掉物理世界中的雜質,再配合虛擬世界的靈活特性,達到最貼近真實的體驗。

Google play就是基於Material Design所設計的
使用Material Design能夠大幅度的增加我們程式的介面的美觀度和與使用者的互動性,所以在Android進階的第一章就來學習一下Material Design中幾個常用的控制元件吧!
Toolbar
Toolbar簡單來說就是一個可以編輯的ActionBar。ActionBar就是簡單來說就是每個活動最上面的那個標題欄,我們之前在初步學習Android的時候所建立的佈局使用的都是ActionBar。由於ActionBar被其自身的設計原因所限制,所以我們很難在它身上做“手腳”,因此在Material Design中就引入了Toolbar。
如果我們要使用Toolbar,那麼第一步要做的就是將系統預設的ActionBar給替換掉。我們新建一個專案,然後開啟res—values—styles.xml,會看到顯示如下內容:
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources>
這裡我們著重看到<style name>這個標籤,在這個標籤裡面我們是來定義我們APP的總體主題的,這裡可以看到我們系統預設的主題是淺色(Light)的帶深色Action-Bar(DarkActionBar)的頁面,如果我們不想用ActionBar,就可以在這裡修改。
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!--修改程式碼-> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources>
我們將主題修改為淺色的不帶ActionBar。接著我們看到這個裡面的其他屬性,這些屬性所代表的意思我們可以用一張圖來解釋:

各個屬性
接著我們就可以在佈局中將Toolbar新增進去了:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" 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.v7.widget.Toolbar> </FrameLayout>
首先是在開頭我們定義了一個xmlns:app名稱空間,有了它我們就可以在後面的屬性中使用app這個空間了,這樣做的好處就是能夠讓 Material Design相容低系統的手機。接著就是新增Toolbar這個控制元件了,這裡面的屬性設定我們可能之前從來沒有遇到過,所以這裡來分別的解釋一下:
- android:layout_height="?attr/actionBarSize"
在設定控制元件的高度時我們傳入的值是?attr/actionBarSize
,它的意思是指我們讓Toolbar的寬度和原來的ActionBar的寬度保持一致。 - android:background="?attr/colorPrimary"
在設定控制元件的背景顏色時我們傳入的引數是?attr/colorPrimary
,它的意思是我們的顏色要和colorPrimary的顏色保持一致。 - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
這個屬性是用來設定我們控制元件的主題的,在這裡我們使用的是深色ActionBar主題。 - app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
在這裡我們使用了app的名稱空間,這個屬性主要是用來設定我們Toolbar中的選單項的顏色主題的。
上面這些完成之後,我們就成功的將ActionBar替換成了Toolbar了,接下來就可以來為Toolbar新增功能了。我們先來在它的右上角新增幾個按鈕和選單。我們點選res—new—Diectory來建立一個menu,接著在menu下新建一個Menu resource,然後修改程式碼:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/backup" android:icon="@drawable/ic_launcher_background" android:title="Backup" app:showAsAction="always"/> <item android:id="@+id/delete" android:icon="@drawable/ic_launcher_background" android:title="Delete" app:showAsAction="always"/> <item android:id="@+id/settings" android:icon="@drawable/ic_launcher_background" android:title="Settings" app:showAsAction="never"/> </menu>
我們還是先在開始添加了app的名稱空間,然後就是為menu新增控制元件,這裡面的屬性我們大多數都是見過的,只有 app:showAsAction
這一項,它的意思是指控制元件是否展示出來,一般都是有三個引數可以選擇:always(一直都展示出來)、ifRoom (如果有位置就展示出來,沒有位置就放在摺疊欄裡面)和never(一直放在摺疊欄裡面不展示出來),需要注意的時如果使用的never則我們為它設定的背景圖片是無法再摺疊欄中展示出來的。
接著我們修改主程式碼,將menu載入進佈局:
package com.example.yzbkaka.toolbartest; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); setSupportActionBar(toolbar);//啟用Toolbar } public boolean onCreateOptionsMenu(Menu menu){//載入menu getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item){//menu子項的點選事件 switch (item.getItemId()){ case R.id.backup: Toast.makeText(this, "backup", Toast.LENGTH_SHORT).show(); break; case R.id.delete: Toast.makeText(this, "delete", Toast.LENGTH_SHORT).show(); break; case R.id.settings: Toast.makeText(this, "setting", Toast.LENGTH_SHORT).show(); break; default: break; } return true; } }
我們先是使用了setSupportActionBar()的方法來將Toolbar啟用,接著就是重寫onCreateOptionsMenu()和onOptionsItemSelected()方法來分別將menu載入進來和為menu中的子項新增點選時間。
滑動選單
滑動選單在我們現在使用的大多數app裡面都可以見到,它就是在程式的介面中用手指在靠近螢幕左邊的地方向右滑動即可出現一個選單欄,在這個選單欄中我們可以新增點選事件和圖片等控制元件。
我們在佈局中修改程式碼:
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout 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.v7.widget.Toolbar> </FrameLayout> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" android:background="#fff" android:textSize="30sp" android:text="Hello"/> </android.support.v4.widget.DrawerLayout>
我們在這裡使用的是DrawerLayout這個佈局的排列方式,這個佈局是允許我們放入兩個直接的子控制元件的:第一個子控制元件就是在主螢幕中顯示的內容;第二個子控制元件就是我們滑動選單的內容了。這裡我們是將TextView新增到滑動選單中,主要在設定第二個子控制元件時我們必須要設定 android:layout_gravity
這個屬性,它是來設定選單是從左向右滑動還是從右向左滑動出現的,left表示選單在螢幕的左邊,right表示選單在螢幕的右邊,而start則是系統自動進行判斷。
接下來來我們就來對滑動選單中新增控制元件。Android官方推薦我們使用Navigation-View來對滑動選單進行編輯,它是由Design Support庫中提供的,因此我們需要先為我們的程式新增依賴,在dependencise閉包中新增:
implementation 'com.android.support:design:26.1.0'
然後我們來對滑動選單進行修改吧!具體的規劃是在滑動選單的上部新增一張圖片,而在下部就是新增相應menu以及點選事件。我們先從上部開始,在layout—new—Layout resource中新建一個nav_header.xml的佈局,然後修改程式碼:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="180dp" android:padding="10dp" android:background="@drawable/bing"> </RelativeLayout>
我們將header的寬度設定為 match_parent
,而高度設定為180dp,這是對於header來說比較合適的設定。然後在背景上我是選擇了一張bing的背景圖片,並且讓它的四周有著10dp的留白。
接著就是來為滑動選單新增menu了,我們在menu資料夾中新建一個目錄,然後是修改程式碼:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/name" android:title="name"/> <item android:id="@+id/call" android:title="call"/> <item android:id="@+id/email" android:title="email"/> <item android:id="@+id/age" android:title="age"/> </menu>
我們在這裡是新增幾個簡單的子項。接著是修改主佈局:
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout 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.v7.widget.Toolbar> </FrameLayout> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" app:menu="@menu/nav_menu" app:headerLayout="@layout/nav_header"> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
在滑動選單欄的那一項佈局當中,我們使用 app:menu
和 app:headerLayout
屬性將我們之前建立好的佈局給添加了進去。最後就是修改主程式碼了:
package com.example.yzbkaka.toolbartest; import android.support.design.widget.NavigationView; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); setSupportActionBar(toolbar); NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view);//獲取例項 navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {//設定監聽 @Override public boolean onNavigationItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.name: Toast.makeText(MainActivity.this, "name", Toast.LENGTH_SHORT).show(); break; caseR.id.call: Toast.makeText(MainActivity.this, "call", Toast.LENGTH_SHORT).show(); break; case R.id.email: Toast.makeText(MainActivity.this, "email", Toast.LENGTH_SHORT).show(); break; case R.id.age: Toast.makeText(MainActivity.this, "age", Toast.LENGTH_SHORT).show(); break; } return true; } }); } public boolean onCreateOptionsMenu(Menu menu){ getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item){ switch (item.getItemId()){ case R.id.backup: Toast.makeText(this, "backup", Toast.LENGTH_SHORT).show(); break; case R.id.delete: Toast.makeText(this, "delete", Toast.LENGTH_SHORT).show(); break; case R.id.settings: Toast.makeText(this, "setting", Toast.LENGTH_SHORT).show(); break; default: break; } return true; } }
我們先是獲取到NavigationView的例項,然後就是使用setNavigationItemSelected-Listener()為該例項新增監聽和相應的點選事件。
現在我們就將滑動選單給設定好了,但是還會存在這樣一種情況,即使用者可能不知道我們的程式存在一個滑動選單,因此我們最後再來在左上角設定一個按鈕,當點選之後能夠自動的將滑動選單顯示出來。我們直接修改主程式碼:
package com.example.yzbkaka.toolbartest; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private DrawerLayout drawerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); setSupportActionBar(toolbar); NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.name: Toast.makeText(MainActivity.this, "name", Toast.LENGTH_SHORT).show(); break; caseR.id.call: Toast.makeText(MainActivity.this, "call", Toast.LENGTH_SHORT).show(); break; case R.id.email: Toast.makeText(MainActivity.this, "email", Toast.LENGTH_SHORT).show(); break; case R.id.age: Toast.makeText(MainActivity.this, "age", Toast.LENGTH_SHORT).show(); break; } return true; } }); drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);//獲取例項 ActionBar actionBar = getSupportActionBar(); if(actionBar != null){ actionBar.setDisplayHomeAsUpEnabled(true);//讓按鈕顯示出來 } } public boolean onCreateOptionsMenu(Menu menu){ getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item){ switch (item.getItemId()){ case R.id.backup: Toast.makeText(this, "backup", Toast.LENGTH_SHORT).show(); break; case R.id.delete: Toast.makeText(this, "delete", Toast.LENGTH_SHORT).show(); break; case R.id.settings: Toast.makeText(this, "setting", Toast.LENGTH_SHORT).show(); break; case android.R.id.home://新增點選事件 drawerLayout.openDrawer(GravityCompat.START); break; default: break; } return true; } }
我們在這裡先是獲取到了DrawerLayout例項,然後是得到一個ActionBar的物件,並且使用該物件的setDisplayHomeAsUpEnabled()方法來讓導航按鈕顯示出來,最後就是為該按鈕新增點選事件了,我們這裡是使用openDrawer()方法來開啟滑動選單的,在這裡需要注意的是導航按鈕相當於是系統內建的,因此它的id永遠是 android.R.id.home
。
懸浮按鈕
我們接著來修改我們的介面。有的時候我們使用新聞類APP時,當我們往下瀏覽新聞時在我們的螢幕右下角會出現一個圓形的按鈕,我們可以點選它之後馬上回到APP的頂端進行重新整理。這樣一個按鈕就是懸浮按鈕。
懸浮按鈕的新增方法也是非常簡單的,我們先修改主佈局程式碼:
...... <FrameLayout 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.v7.widget.Toolbar> <android.support.design.widget.FloatingActionButton android:id="@+id/float_action_button" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="bottom|end" android:layout_margin="16dp" /> </FrameLayout> ......
我們直接在之前的專案中的<FrameLayout>標籤中新增FloatingActionButton這個元件。其中 android:layout_gravity="bottom|end"
的意思是指將這個控制元件放在螢幕的右下角。 android:layout_margin="16dp"
則是來設定控制元件距離螢幕四周的間距的。
接著我們來修改主程式碼,給懸浮按鈕新增點選事件:
...... FloatingActionButton floatingActionButton = (FloatingActionButton)findViewById(R.id.float_action_button); floatingActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "folatingActionButton", Toast.LENGTH_SHORT).show(); } }); ......
懸浮按鈕的點選方法也是很簡單的,與普通按鈕的設定方法是一樣的,這裡我們就是簡單的設定一段短訊息提醒即可。
OK,到這裡我們就使用Material Design編寫出了一個漂亮的介面了,但是Material Design中的控制元件遠不止這麼一點,所以如果想要了解更多的知識和控制元件的話,可以訪問 Material Design官方介紹 。