1. 程式人生 > >Material Design控制元件使用(一)

Material Design控制元件使用(一)

最近學習了一下md設計風格和相對應的控制元件覺得挺棒的,真希望以後能做安卓設計風格的app,只是心有魚而力不足,雖身為安卓程式設計師但由於公司設計成本卻每天做著ios風格的app,這感覺真是(此處省略一萬字)…,既然公司的專案沒法過把癮,那就自己做的玩,本篇部落格要實現的效果如下,由於上傳圖片大小2m的限制效果非常不好但是效果基本顯示了
這裡寫圖片描述
要完成如上效果需要掌握的新控制元件
1.Toolbar
2.CollapsingToolbarLayout
3.AppBarLayout
4.CoordinatorLayout
5.DrawerLayout
6.NavigationView
7.ActionBarDrawerToggle
8.Recyclerview
9.CardView
看來要想實現需要掌握的東西挺多的,不過別擔心下面我會一一介紹每個控制元件的使用並逐步實現該效果
萬里長征第一步開始啦

1.Toolbar

用toolbar之前首先要將主題改為md風格的
Material Design的Theme
md的主題有:
•@android:style/Theme.Material (dark version)
•@android:style/Theme.Material.Light (light version)
•@android:style/Theme.Material.Light.DarkActionBar

與之對應的Compat Theme:
•Theme.AppCompat
•Theme.AppCompat.Light
•Theme.AppCompat.Light.DarkActionBar
當然為了相容低版本我們使用compat theme
先在res/values/styles.xml 中增加一個名為AppThemeBase的style

<style name="AppThemeBase" parent="Theme.AppCompat.Light">
        <!-- 去掉actionbar-->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <!-- 狀態列顏色-->
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item
> <!-- actionbar顏色--> <item name="colorPrimary">@color/colorPrimary</item> </style>

既然要使用toolbar就得隱藏actionbar

<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>

顏色設定對應下圖
這裡寫圖片描述
這裡寫圖片描述
然後將原本 AppTheme 的 parent 屬性 改為上面的AppThemeBase,完整程式碼如下:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="AppThemeBase">
    </style>

    <style name="AppThemeBase" parent="Theme.AppCompat.Light">
        <!-- 去掉actionbar-->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <!-- 狀態列顏色-->
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <!-- actionbar顏色-->
        <item name="colorPrimary">@color/colorPrimary</item>

    </style>

</resources>

使用的顏色檔案如下

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimaryDark">#0288D1</color>
    <color name="colorPrimary">#03A9F4</color>
    <color name="colorAccent">#03A9F4</color>
    <color name="primaryText">#212121</color>
    <color name="secondaryText">#727272</color>
    <color name="dividerColor">#B6B6B6</color>
</resources>

佈局中新增layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context="com.byzk.www.test.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        />

</LinearLayout>

這裡說明一下?attr/代表引用當前主題的屬性
?attr/actionBarSize -> 當前主題下actionbar高度系統自帶的
?attr/colorPrimary -> 當前主題下colorPrimary顏色
並且toolbar為v7包的

再來activity程式碼

package com.byzk.www.test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findView();
        init();
    }

    private void findView() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
    }

    private void init() {
        setSupportActionBar(toolbar);
    }
}

實現非常簡單就兩步
1.toolbar = (Toolbar) findViewById(R.id.toolbar);
2.setSupportActionBar(toolbar);
但是有點要注意要想使用toolbar並且相容低版本,activity必須繼承AppCompatActivity
到這一步實現效果如下
這裡寫圖片描述
距離我們最終要完成toolbar的效果左邊還差ActionBarDrawerToggle右邊還差overflow menu,
先來加上menu
建立res/menu/menu_main.xml

<?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/option_1"
        app:showAsAction="never"
        android:title="選項一" />
    <item
        android:id="@+id/option_2"
        app:showAsAction="never"
        android:title="選項二" />
    <item
        android:id="@+id/option_3"
        app:showAsAction="never"
        android:title="選項三" />
</menu>

activity中新增程式碼如下

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.option_1:
                Toast.makeText(MainActivity.this,"option_1",Toast.LENGTH_SHORT).show();
                break;
            case R.id.option_2:
                Toast.makeText(MainActivity.this,"option_2",Toast.LENGTH_SHORT).show();
                break;
            case R.id.option_3:
                Toast.makeText(MainActivity.this,"option_3",Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }

執行效果如下
這裡寫圖片描述
文字和右邊按鈕顯現出來了..那麼最讓我頭疼的問題來了如何設定他的顏色我也是查了很久試了好多方法都有缺陷最後在stackoverflow找到了解決辦法

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

app:theme=”@style/ThemeOverlay.AppCompat.Dark.ActionBar”->給toolbar設定單獨的主題
app:popupTheme=”@style/ThemeOverlay.AppCompat.Light”->給彈出窗設定主題
雖然設定成功了但是對於style和theme我所知道的還是太少,如果有對於style和theme非常瞭解的同學歡迎交流
那麼到這一步了效果如下
這裡寫圖片描述
還有些圖示標題設定比較簡單我直接貼對應方法了不做演示了
這裡寫圖片描述
setNavigationIcon
即設定 up button 的圖示,因為 Material 的介面,在 Toolbar這裡的 up button樣式也就有別於過去的 ActionBar 哦。

setLogo
APP 的圖示。

setTitle
主標題。

setSubtitle
副標題。

setOnMenuItemClickListener
設定選單各按鈕的動作。

2.DrawerLayout+NavigationView+ActionBarDrawerToggle

toolbar這裡搭建完成了再來加上側滑效果

DrawerLayout
drawerLayout就是一個佈局控制元件並且帶有滑動的功能。只要按照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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.byzk.www.test.MainActivity">

    <!-- 主佈局-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <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" />

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

    <!-- 側邊選單-->
    <FrameLayout
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary"
        android:layout_gravity="start"/>


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

這裡有兩點要注意:
1.主內容區的佈局程式碼要放在側滑選單佈局的前面,
2.側滑選單的部分的佈局需要設定android:layout_gravity=”start”屬性,他表示側滑選單是在左邊還是右邊。
start表示左邊 end表示右邊
效果如下
這裡寫圖片描述
drawerlayout開關可用如下方法控制

drawerLayout.openDrawer();
drawerLayout.closeDrawer();

ActionBarDrawerToggle
drawerLayout左側選單(或者右側)的展開與隱藏可以被DrawerLayout.DrawerListener的實現監聽到,不過還是建議用ActionBarDrawerToggle來監聽,ActionBarDrawerToggle實現了DrawerListener,所以他能做DrawerListener可以做的任何事情,同時他還能將drawerLayout的展開和隱藏與actionbar的app 圖示關聯起來,當展開與隱藏的時候圖示有一定的平移效果,點選圖示的時候還能展開或者隱藏選單。
activity程式碼新增程式碼如下

ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(
                this,
                drawerLayout,
                toolbar,
                R.string.drawer_open,
                R.string.drawer_close
        ){
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                //開啟
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                //關閉
            }
        };
        drawerLayout.setDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();

新增後效果如下
這裡寫圖片描述

NavigationView
左側與drawerlayout關聯的按鈕已經顯現來了,那麼現在在為側滑選單新增內容,其實側滑選單內容使用啥控制元件都可以,只是我這裡準備使用com.android.support:design包的控制元件navigationView所以記得新增依賴
佈局程式碼如下

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawerlayout"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.byzk.www.test.MainActivity">

    <!-- 主佈局-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <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" />

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>

    <!-- 側邊選單-->
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/drawer_header"
        app:menu="@menu/menu_drawer"/>


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

這裡最主要的兩個屬性分別是:
1.app:headerLayout: 給NavigationView新增頭部佈局
2.app:menu:給NavigationView新增menu選單佈局

drawer_header.xml如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="?attr/colorPrimary"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@mipmap/icon" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="帥也是錯嗎"
        android:textColor="#fff"
        android:textSize="16sp" />
</LinearLayout>

menu_drawer.xml如下

<?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_blog"
            android:title="我的部落格" />
        <item
            android:id="@+id/nav_about"
            android:title="關於我" />

        <item
            android:id="@+id/nav_version"
            android:title="版本資訊" />
    </group>

    <item android:title="Sub Title">
        <menu>
            <item
                android:id="@+id/nav_sub1"
                android:title="副標題1"
                android:checkable="true"/>
            <item
                android:id="@+id/nav_sub2"
                android:title="副標題2"
                android:checkable="true"/>
        </menu>
    </item>
</menu>

Activity中控制NavigationView程式碼如下

navigationView.setNavigationItemSelectedListener(new MyNavigationListener());

private class MyNavigationListener implements NavigationView.OnNavigationItemSelectedListener {

        @Override
        public boolean onNavigationItemSelected(MenuItem item) {
            drawerLayout.closeDrawer(GravityCompat.START);
            switch (item.getItemId()) {
                case R.id.nav_blog:
                    break;
                case R.id.nav_about:
                    break;
                case R.id.nav_version:
                    break;
                case R.id.nav_sub1:
                    break;
                case R.id.nav_sub2:
                    break;
            }
            return true;
        }
    }

顯示效果如下
這裡寫圖片描述
正如actionbar一樣NavigationView用起來是非常方便但是這個控制元件也有很多弊病,尤其是在文字圖示自定義方面,如果你有這個需求那麼側滑佈局用listview或者framelayout+fragment實現更好這裡不多介紹了

3.CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+RecyclerView+CardView

AppBarLayout
終於距離目標越來越近了.接下來完成的是toolbar上面那個摺疊效果
AppBarLayout 是繼承LinerLayout實現的一個ViewGroup容器元件,它是為了Material Design設計的App Bar,支援手勢滑動操作。它的作用是把AppBarLayout包裹的內容都作為AppBar
注意: AppBarLayout必須作為Toolbar的父佈局容器
AppBarLayout是支援手勢滑動效果的,不過得跟CoordinatorLayout配合使用,相關程式碼在後面一起貼出

CoordinatorLayout
CoordinatorLayout是一個增強型的FrameLayout。它的作用有兩個
1.作為一個佈局的根佈局
2.作為各個子類協調手勢操作的一個協調佈局(從它的名字就可以看出來)
佈局程式碼

<?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/drawerlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.byzk.www.test.MainActivity">

    <!-- 主佈局-->
    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="180dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="120dp"
                android:background="@drawable/bg"
                app:layout_scrollFlags="scroll|enterAlways"
                />

            <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" />
        </android.support.design.widget.AppBarLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

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

    <!-- 側邊選單-->
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/drawer_header"
        app:menu="@menu/menu_drawer" />


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

activity並沒新增什麼程式碼只是給recycleview添加了些資料
效果如下
這裡寫圖片描述
從佈局上面可以看到CoordinatorLayout包裹了Appbar和可以滑動的佈局
為了達到上面效果圖的手勢動畫效果,我們必須做如下設定

1.通過app:layout_scrollFlags=”scroll|enterAlways” 屬性來確定哪個元件是可滑動的並且如何滑動
layout_scrollFlags有如下幾種選項:
•scroll: 所有想滾動出螢幕的view都需要設定這個flag
•enterAlways: 這個flag讓任意向下的滾動都會導致該view變為可見,啟用快速“返回模式”。
•enterAlwaysCollapsed: 當你的檢視已經設定minHeight屬性又使用此標誌時,你的檢視只能已最小高度進入,只有當滾動檢視到達頂部時才擴大到完整高度。(還沒研究明白)
•exitUntilCollapsed: 只有滑動到最頂端在向下滾動會導致該view變為可見

我們上面的佈局中 給ImageView設定了app:layout_scrollFlags屬性,因此,ImageView是可以滾動出螢幕,且向下滾動就可以出現。

2.我們必須還得有個條件,就是CoordinatorLayout佈局下包裹一個可以滑動的佈局,比如 RecyclerView,NestedScrollView(經過測試,ListView,ScrollView不支援)具有滑動效果的元件。並且給這些元件設定如下屬性來告訴CoordinatorLayout,該元件是帶有滑動行為的元件,然後CoordinatorLayout在接受到滑動時會通知AppBarLayout 中可滑動的Imageview可以滑出螢幕了。

app:layout_behavior="@string/appbar_scrolling_view_behavior"

總結一下:
1.要使用CoordinatorLayout作為父佈局
2.相應滑動事件的控制元件需要新增app:layout_scrollFlags=”scroll|enterAlways”屬性。
3.包裹的滑動控制元件需要新增app:layout_behavior=”@string/appbar_scrolling_view_behavior”屬性

CollapsingToolbarLayout
如果想製造toolbar的摺疊效果,我們必須把Toolbar放在CollapsingToolbarLayout中,它一般作為AppBarLayout的子佈局:
佈局程式碼如下

<?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/drawerlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.byzk.www.test.MainActivity">

    <!-- 主佈局-->
    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="180dp"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsingToolBarLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:contentScrim="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">


                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/bg"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.6" />

                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

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

    <!-- 側邊選單-->
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/drawer_header"
        app:menu="@menu/menu_drawer" />


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

CollapsingToolbarLayout 提供以下屬性和方法是用:
1.Collapsing title:ToolBar的標題,當CollapsingToolbarLayout全屏沒有摺疊時,title顯示的是大字型,在摺疊的過程中,title不斷變小到一定大小的效果。你可以呼叫setTitle(CharSequence)方法設定title。通常,我們我們都是設定Toolbar的title,而現在,我們需要把title設定在CollapsingToolBarLayout上,而不是Toolbar。

2.Content scrim:ToolBar被摺疊到頂部固定時候的背景,你可以呼叫setContentScrim(Drawable)方法改變背景或者 在屬性中使用 app:contentScrim=”?attr/colorPrimary”來改變背景,這裡需要注意toolbar不能有背景不然toolbar背景會始終顯示在頂部.

3.Parallax scrolling children:CollapsingToolbarLayout滑動時,子檢視的視覺差,可以通過屬性app:layout_collapseParallaxMultiplier=”0.6”改變。(感覺沒啥用)

4.CollapseMode :子檢視的摺疊模式,有兩種“pin”:固定模式,在摺疊的時候最後固定在頂端;“parallax”:視差模式,在摺疊的時候會有個視差摺疊的效果。我們可以在佈局中使用屬性app:layout_collapseMode=”parallax”來改變。

經過我個人的測試ImageView只能放在ToolBar的上面才會有效果,還不明白為啥
CollapsingToolbarLayout主要是提供一個可摺疊的Toolbar容器,對容器中的不同View設定layout_collapseMode摺疊模式,來達到不同的摺疊效果。

效果
這裡寫圖片描述