讓你的 APP換上Material Design

Material Design

我的更多 android 博文,關注作者~每周更新一篇 Android干貨博文
http://xuyushi.github.io/archives/

吐槽

作為一個 Android developer,沒有什么比拿著 UI 設計的一堆 iOS 風格的設計 來做需求更惡心的了,基本所有空間都要照著 iOS 來畫一遍,Material Design 辣么酷炫 為什么 UI在設計的階段不設計成 Material Design風格呢?

今天試了幾個比較Support包中比較典型的Material Design控件,后期會在學習下Material Design的設計思想和理念,希望能拉著 UI 做一次Material Design 分享,改變我們 APP 的 iOS 風格啊。

最終效果如下


Android Design Support 庫依賴

build.gradle 中加入support 包

    compile 'com.android.support:appcompat-v7:23.1.1'

Design Support Library 中包含了 Support v4 和 AppCompat v7

Floating Action Button

我們希望FloatingActionButton懸浮在頁面的右下方,所以我們父節(jié)點應使用Flowlayout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="io.github.xuyushi.materialdesigndemo.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:src="@android:drawable/ic_dialog_email" />

</FrameLayout>

和普通 button 一樣可以設置其點擊事件

private void initFb() {
        mFb = (FloatingActionButton) findViewById(R.id.fb);
        mFb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "fb  predsed ", Toast.LENGTH_SHORT).show();
            }
        });
    }

Android:elevation屬性為 view 在空閑狀態(tài)下的陰影深度, 需要在 api 21以上才能使用,使用 support 包可以使用app:elevation 來表示空閑狀態(tài)高度,app:pressedTanslationZ為按下狀態(tài)的高度

按鈕的顏色一般為主題的強調(diào)色,也可以使用 ”app:backgroundTint“修改

Snackbar

和 Toast 很像,snackbar 可以展示一段簡單的信息,不同點是它的展示更像是整體 UI 的一部分,不是想 toast 一樣是浮在 UI 上的,并且可以有簡單的交互

在點擊 floatingActionButton時顯示Snackbar

但是可以看到,Snackbar 遮擋住了我們的 view,這時候需要一個CoordinatorLayout來協(xié)調(diào) view 布局

CoordinatorLayout

將父布局中的framelaout換成CoordinatorLayout,其他不變,再來看看效果

==todo CoordinatorLayout學習==

Toolbar

Toolbar 比傳統(tǒng)的 ActionBar 更靈活,功能也更多,我們可以看到現(xiàn)在市面上很多的 APP 已經(jīng)用 Toolbar 替代了 actionbar,在 Desgin Support 的組件中,很多設計都可以和 Toolbar 協(xié)同工作,而不是和 actionbar,所以還是建議使用新的 toolbar 替換以前的 actionbar

替換步驟

1、在 minifest 中,將 activity 的 apptheme 的 style 中的 actionbar屬性去掉

<style name="AppTheme.NoActionBar">
   <item name="windowActionBar">false</item>
   <item name="windowNoTitle">true</item>
</style>
    
<activity android:name=".MainActivity">
       <intent-filter>
           <action android:name="android.intent.action.MAIN" />

           <category android:name="android.intent.category.LAUNCHER" />
       </intent-filter>
   </activity>

  1. 在 fb 之前放入 Toolbar 組件
<android.support.design.widget.CoordinatorLayout 
    .........

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:src="@android:drawable/ic_dialog_email"
        app:elevation="12dp"
        app:pressedTranslationZ="30dp"
        />


</android.support.design.widget.CoordinatorLayout>

  1. 通知系統(tǒng)使用 toolbar
    private void initToolbar() {
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
    }

CoordinatorLayout中的 view 必須是能一同協(xié)作的 view,就像 Snackbar 一樣,但是 toolbar 并不是這樣能協(xié)同作戰(zhàn)的 view,所以我們需要用一個可以協(xié)同作戰(zhàn)的 view 來包裹上Toolbar,這就是 AppBarLayout

現(xiàn)在我們的布局文件結(jié)構是這樣的

<android.support.design.widget.CoordinatorLayout
    ...>
 
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
       <android.support.v7.widget.Toolbar
           .../>
    </android.support.design.widget.AppBarLayout>
 
    <android.support.design.widget.FloatingActionButton
        ...>
    </android.support.design.widget.FloatingActionButton>
</android.support.design.widget.CoordinatorLayout>

注意

根據(jù)官方的谷歌文檔,AppBarLayout目前必須是第一個嵌套在CoordinatorLayout里面的子view

在 toolbar 中加入屬性,app:layout_collapseMode="pin",使得 Toolbar 中的按鈕能固定在頂部

在布局中加入內(nèi)容

在布局中嘗試加入一些按鈕

....
 </android.support.design.widget.AppBarLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:orientation="vertical">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="test" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="test" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="test" />

    </LinearLayout>
    ...

我們定義三個按鍵,卻被 toolbar 遮住了一個,原因是LinearLayout并沒有被設計成在CoordinatorLayout協(xié)同工作的模式,為了使他們能在CoordinatorLayout協(xié)同工作,我們需要在LinearLayout加上一條屬性,來告訴它的滾動屬性()

<LinearLayout
    ...
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    ...
    >

搞定

TabLayout

根據(jù)官網(wǎng)的知道,TabLayout通常應該是放在頂部,(iOS 的 tab 好像基本在底部),
他應該在陰影部分上面,所以應該放在AppBarlayout

<android.support.design.widget.AppBarLayout ...>
    <android.support.v7.widget.Toolbar ... />
    <android.support.design.widget.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>

java 中設置這些 tab 屬性

private void initTableLayout() {
   mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
   mTabLayout.addTab(mTabLayout.newTab().setText("Tab 1"));
   mTabLayout.addTab(mTabLayout.newTab().setText("Tab 2"));
   mTabLayout.addTab(mTabLayout.newTab().setText("Tab 3"));
}

背景會設置為主題色,導航線是強調(diào)色。但是字還是黑色的,因為我們沒有為 tablayout 定義主題,

<android.support.design.widget.TabLayout
    ...
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

通常 tablayout 會和ViewPager一起使用 ,這時候使用
public void setupWithViewPager (ViewPager viewPager)

一張圖看的比較清晰


內(nèi)容滾動時,AppBarLayout隱藏

當滑檔內(nèi)容時,為了騰出跟多的空間展示內(nèi)容可以將AppBarLayout隱藏

1.用 scrollView 包裹 LinearLayout,記得加上 app:layout_behavior屬性

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        ...
    </LinearLayout>
</ScrollView>
  1. Toolbar 加上屬性
<android.support.v7.widget.Toolbar
    ...
    app:layout_scrollFlags="scroll|enterAlways" />
  1. scrollView 也不能喝 CoordinatorLayout 協(xié)同工作,同上面一樣,要用別的 view 包裹或者直接使用 NestedSrollView替換scrollView

如果希望 tablayout 也消失,只需要和 tablayout 加上相同的屬性就行了

<android.support.design.widget.TabLayout
    ...
    app:layout_scrollFlags="scroll|enterAlways" />

滑動內(nèi)容 和 AppBarLayout是如何進行聯(lián)系的?

我們需要定義AppBarLayout與滾動視圖之間的聯(lián)系。在RecyclerView或者任意支持嵌套滾動的view比如NestedScrollView上添加app:layout_behavior。support library包含了一個特殊的字符串資源@string/appbar_scrolling_view_behavior,它和AppBarLayout.ScrollingViewBehavior相匹配,用來通知AppBarLayout 這個特殊的view何時發(fā)生了滾動事件,這個behavior需要設置在觸發(fā)事件(滾動)的view之上

當CoordinatorLayout發(fā)現(xiàn)scrollView中定義了這個屬性,它會搜索自己所包含的其他view,看看是否有view與這個behavior相關聯(lián)。AppBarLayout.ScrollingViewBehavior描述了RecyclerView與AppBarLayout之間的依賴關系。RecyclerView的任意滾動事件都將觸發(fā)AppBarLayout或者AppBarLayout里面view的改變。

AppBarLayout里面定義的view只要設置了app:layout_scrollFlags屬性,就可以在RecyclerView滾動事件發(fā)生的時候被觸發(fā):

app:layout_scrollFlags屬性里面必須至少啟用scroll這個flag,這樣這個view才會滾動出屏幕,否則它將一直固定在頂部。可以使用的其他flag有:

  • enterAlways: 一旦向上滾動這個view就可見。
  • enterAlwaysCollapsed: 顧名思義,這個flag定義的是何時進入(已經(jīng)消失之后何時再次顯示)。假設你定義了一個最小高度(minHeight)同時enterAlways也定義了,那么view將在到達這個最小高度的時候開始顯示,并且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。
  • exitUntilCollapsed: 同樣顧名思義,這個flag時定義何時退出,當你定義了一個minHeight,這個view將在滾動到達這個最小高度的時候消失。

記住,要把帶有scroll flag的view放在前面,這樣收回的view才能讓正常退出,而固定的view繼續(xù)留在頂部。

可折疊的 Toolbar

  • 用 CollapsingToolbarLayout 包裹 Toolbar,但仍然在 AppBarLayout 中
  • 刪除 Toolbar 中的 layout_scrollFlags
  • 為 CollapsingToolbarLayout 聲明 layout_scrollFlags,并且將 layout_scrollFlags 設置成 scroll|exitUntilCollapsed
<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="256dp">
 
    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsingToolbarLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">
 
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" 
            app:layout_collapseMode="pin"/>
 
    </android.support.design.widget.CollapsingToolbarLayout>
 
</android.support.design.widget.AppBarLayout>

注意 CollapsingToolbarLayout 的高度是android:layout_height="match_parent"

CollapsingToolbarLayout在展開和收縮時,標題的文字會自動過度的,可以通過 app:expandedTitleMargin 等來改變文字位置

為 appBar 添加背景圖片

由于 CollapsingToolbarLayout 是繼承 Framelayout 的,所以我們可以直接添加一個 ImageView 作為背景圖片

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:src="@drawable/header" />
 
<android.support.v7.widget.Toolbar
    ...

此時雖然背景已經(jīng)出來了,但是藍色的導航條依舊存在,需要在 toolbar 去掉這條屬性

android:background="?attr/colorPrimary"

給 Imageview 加上視差模式會更帥

app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5"

也可以在最后恢復成主題色

<android.support.design.widget.CollapsingToolbarLayout
    ...
    app:contentScrim="?attr/colorPrimary">

Navigation Drawer

AppBarLayout布局下,增DrawerLayout

<android.support.design.widget.AppBarLayout>
...

<android.support.v4.widget.DrawerLayout 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"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:openDrawer="start">

        <include layout="@layout/content_main" />

        <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_main2"
            app:menu="@menu/activity_main2_drawer" />

    </android.support.v4.widget.DrawerLayout>

DrawerLayout中分兩部分組成,一部分是content 就是我們需要的主布局內(nèi)容,另一部分是我們的抽屜的布局,NavigationView中有頂部頭,和標簽

app:headerLayout="@layout/nav_header_main2"
            app:menu="@menu/activity_main2_drawer"

創(chuàng)建菜單。

菜單元素是放在group標簽之下,同時聲明每次只能有一個item被選中:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_camera"
            android:icon="@drawable/ic_menu_camera"
            android:title="Import" />
        <item
            android:id="@+id/nav_gallery"
            android:icon="@drawable/ic_menu_gallery"
            android:title="Gallery" />
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="Slideshow" />
        <item
            android:id="@+id/nav_manage"
            android:icon="@drawable/ic_menu_manage"
            android:title="Tools" />
    </group>

    <item android:title="Communicate">
        <menu>
            <item
                android:id="@+id/nav_share"
                android:icon="@drawable/ic_menu_share"
                android:title="Share" />
            <item
                android:id="@+id/nav_send"
                android:icon="@drawable/ic_menu_send"
                android:title="Send" />
        </menu>
    </item>

</menu>

為了防止頁面被遮蓋,同樣要使得 DrawerLayout協(xié)調(diào)。加入app:layout_behavior="@string/appbar_scrolling_view_behavior"屬性

java初始化

private void initDraw() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem item) {
                // Handle navigation view item clicks here.
                int id = item.getItemId();

                if (id == R.id.nav_camera) {
                    // Handle the camera action
                } else if (id == R.id.nav_gallery) {

                } else if (id == R.id.nav_slideshow) {

                } else if (id == R.id.nav_manage) {

                } else if (id == R.id.nav_share) {

                } else if (id == R.id.nav_send) {

                }

                DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
                drawer.closeDrawer(GravityCompat.START);
                return true;
            }
        });

SwipeRefreshLayout

NestedScrollView外在包裹一層SwipeRefreshLayout,

  <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true"
            >
            .....
        </android.support.v4.widget.NestedScrollView>

    </android.support.v4.widget.SwipeRefreshLayout>

初始化監(jiān)聽器

private void initRefresh() {
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshContent();
            }
        });
    }

    private void refreshContent() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
            }
        }, 2000);
    }

我的更多 android 博文,關注作者~每周更新一篇 Android干貨博文
http://xuyushi.github.io/archives/

參考

http://inthecheesefactory.com/blog/android-design-support-library-codelab/en
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0717/3196.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0608/3011.html
http://developer.android.com/design/material/

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容