自從 Google I/O 2014 釋出 Material Design 到現在,這個設計語言已經相當完善了。Material Design 是我最喜歡的一種設計,在專案中,我會盡可能的使用 Material Design 的控制元件。
下面給大家簡單介紹一下「冰與火百科」裡面涉及到的 Material Design 控制元件。
側滑選單
APP 裡需要一個切換內容以及設定的地方,使用側滑選單是最好的選擇。過去我們都是用 SlidingMenu 這樣的第三方控制元件實現側滑選單,隨著 Design 庫的釋出,我們有了官方的側滑選單。
在 Android Studio 裡新建專案的時候,可以直接選擇帶有側滑選單的模板:
如果沒有選模板,記得在 build.gradle 新增設計庫的依賴:
compile "com.android.support:design:${SUPPORT_LIB_VERSION}"複製程式碼
DrawerLayout
我們看一下首頁的佈局:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>複製程式碼
DrawerLayout 包含了主檢視及側滑選單,負責控制側滑的效果。而 NavigationView 就是我們的側滑選單。
如果使用了 ToolBar,並且要實現側滑選單的狀態和 ToolBar 上的按鈕聯動,像這樣:
在初始化的時候加入如下程式碼就可以實現了:
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this,
drawerLayout,
toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();複製程式碼
NavigationView
從 NavigationView 的佈局屬性可以看出,它由頭部 headerLayout 及選單列表 menu 兩部分組成。
頭部 headerLayout 就是一個普通佈局,通常用漸變色或者圖片來作背景,在上面顯示程式名或使用者資訊。
下面的選單列表,需要引入一個 menu 配置檔案,這個檔案我是這樣寫的:
<?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">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_person"
android:checked="true"
android:icon="@drawable/menu_person"
android:title="人物" />
<item
android:id="@+id/nav_house"
android:icon="@drawable/menu_house"
android:title="家族" />
<item
android:id="@+id/nav_history"
android:icon="@drawable/menu_history"
android:title="歷史" />
<item
android:id="@+id/nav_castles"
android:icon="@drawable/menu_castle"
android:title="城堡" />
<item
android:id="@+id/nav_night"
android:checkable="false"
android:icon="@drawable/menu_bulb"
android:title="夜間模式"
app:actionLayout="@layout/menu_switch" />
</group>
</menu>複製程式碼
前四項是用於切換顯示不同型別的單選按鈕。
最後一項是夜間模式的切換按鈕。它不可點選,並且通過 actionLayout 引入了另一個佈局,佈局裡是一個開關控制元件 SwitchCompat。
Listener
給 NavigationView 設定監聽器,可以實現對側邊欄選單的點選監聽:
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_person:
//...
break;
case R.id.nav_night:
boolean isChecked = switchCompat.isChecked();
switchCompat.setChecked(!isChecked);
break;
}
return true;
}
});複製程式碼
順便說一下這裡 switchCompat 的獲取:
Menu menu = navigationView.getMenu();
MenuItem nightItem = menu.findItem(R.id.nav_night);
View nightView = MenuItemCompat.getActionView(nightItem);
SwitchCompat switchCompat = (SwitchCompat) nightView.findViewById(R.id.switch_compat);複製程式碼
側滑選單相關程式碼基本就這些了,看一下最終的實現效果:
標籤選項卡
過去要實現頂部標籤欄,也是隻能依賴第三方庫,現在有了 TabLayout,可以很簡單就實現這個效果。
佈局如下:
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:theme="@style/ThemeOverlay.AppCompat.Dark" />複製程式碼
設定 tabMode 為 scrollable,讓標籤欄寬度超過佔用的寬度時可以滾動,不然會將所有標籤壓縮在佔用的寬度裡。
我們知道選項卡是要和 ViewPager 搭配使用的,在初始化時加一句讓它們關聯起來就行了:
tabLayout.setupWithViewPager(viewPager)複製程式碼
這麼簡單又實現了一個功能:
下拉重新整理
相信很多人都接觸過 PullToRefresh 這樣的第三方下拉重新整理控制元件,現在我們來看看 Material Design 的下拉重新整理 SwipeRefreshLayout。
在佈局裡用 SwipeRefreshLayout 包裹要實現下拉重新整理的區域,到頂部下拉便會出現載入框,並觸發監聽器的 onRefresh 方法。我們這樣來監聽下拉重新整理:
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
load();
}
};複製程式碼
可以通過 setRefreshing 方法主動開始或停止重新整理。
效果如下:
可摺疊標題欄
在 APP 裡,經常會有一個標題欄,用於顯示頁面標題、放置搜尋或設定按鈕。它的作用不言而喻,但在寸土寸金的螢幕裡它卻一直佔據著一塊固定的區域。現在,我們能夠實現在合適的時候將標題欄摺疊起來。下面簡單介紹一下涉及到的幾個控制元件。
Toolbar
經過 TitleBar、ActionBar 的發展,現在我們用 Toolbar 來實現標題欄:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>複製程式碼
在程式碼中初始化:
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// 設定左邊按鈕可點選
actionBar.setDisplayHomeAsUpEnabled(true);
}複製程式碼
AppBarLayout
AppBarLayout 繼承自 LinerLayout,支援滑動。要讓 Toolbar 響應摺疊效果,需要把 AppBarLayout 作為 Toolbar 的父佈局。
被 AppBarLayout 包裹的控制元件,可以設定一個 layout_scrollFlags 屬性,即滑動摺疊的型別。我給 Toolbar 設定了
app:layout_scrollFlags="scroll|enterAlways"複製程式碼
代表頁面向上、向下滾動時,Toolbar 會跟著一起向上、向下滾動,直到完全隱藏或完全顯示。
CoordinatorLayout
單有 AppBarLayout 還不行,還要配合 CoordinatorLayout 使用才能實現摺疊效果。CoordinatorLayout 作為一個上層佈局,用來協調它的子佈局間的互動。
綜合上面幾個控制元件,最終佈局如下:
<?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: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.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:theme="@style/ThemeOverlay.AppCompat.Dark" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>複製程式碼
要和 Toolbar 實現聯動的控制元件,需要實現了 NestedScrollingChild 介面,並且配置「app:layout_behavior="@string/appbar_scrolling_view_behavior"」。這裡常用的控制元件有 SwipeRefreshLayout、NestedScrollView、RecyclerView。
基本都是佈局程式碼,就可以實現這樣的效果:
CollapsingToolbarLayout
除了簡單的將 Toolbar 收起,還可以實現將圖片收縮轉換為 Toolbar 的酷炫效果。要實現這個效果需要使用 CollapsingToolbarLayout,用它包裹 ImageView 和 Toolbar:
<?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:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="@+id/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:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>複製程式碼
CollapsingToolbarLayout 內的控制元件需要設定 layout_collapseMode 屬性,可選值有:
- parallax 視差模式,隨著頁面滾動會有視差摺疊效果
- pin 固定模式,完全摺疊後固定顯示
效果如下:
卡片檢視
在 Material Design 裡有一個概念是「卡片」,而 CardView 就是這個概念的直接體現。
CardView 其實就是一個帶有 MD 風格的 FrameLayout,它可以有水波紋點選效果,可以設定圓角、設定 z 軸高度(陰影)。
用的時候記得新增依賴:
compile "com.android.support:cardview-v7:${SUPPORT_LIB_VERSION}"複製程式碼
用法跟 FrameLayout 是一樣的,下面例子設定了水波紋點選效果以及圓角和 z 軸高度:
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:foreground="?attr/selectableItemBackground"
app:cardCornerRadius="5dp"
app:cardElevation="5dp">
<!--...-->
</android.support.v7.widget.CardView>複製程式碼
共享元素動畫
在 Material Design 裡,希望頁面的跳轉能有一定的連貫性。
如果頁面 A 和頁面 B 擁有同一個元素,在 Android 5.0 之後,我們可以實現一種叫共享元素的過場動畫,這個元素將會從頁面 A 的位置,變換到頁面 B 的位置。
在「冰與火百科」中,首頁列表和詳情頁都顯示了一張人物圖片,就可以這樣做。
在詳情頁的 ImageView 配置一個 transitionName,它是元素轉換的一個標識:
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:transitionName="tran_01"/>複製程式碼
在首頁跳轉的程式碼,修改為:
Pair[] pairs = new Pair[]{new Pair(binding.ivImg, "tran_01")};
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(mainActivity, pairs);
ActivityCompat.startActivity(context, intent, options.toBundle());複製程式碼
這就是共享元素的效果:
小結
藉著寫「冰與火百科」,把 Material Design 的部分常用控制元件歸納了一下。但這裡只說了每個控制元件的基本用法,想有更深入的瞭解,還需要看查閱相關文章。
我不太懂設計,但有了這些控制元件,感覺「冰與火百科」還挺好看的~