DrawerLayout+Toolbar用法初體驗

本文原創,轉載請註明出處。

寫在前面:
因爲剛剛畢業不久,面對編程世界中快速的知識更迭、龐大的知識體系,總覺得有心無力。想學的東西很多,想實踐的技術很多,但是感覺始終處在追追趕趕的狀態中。終於到了週末,拿出來這非常難得的大塊時間,做一次知識總結和技術實踐。

最近公司在重構代碼,包括UI佈局這塊也是,打算採用 DrawerLayout + Toolbar + Statusbar 這種形式展示出來。說來慚愧,其實這三個組件出來很久了,也看過一些資料,不過忘記是從哪裏看到過一句話,那就是“沒有敲過的代碼永遠不屬於自己,並且也不要指望能找到一行都不需要修改的代碼”,我非常認同這句話,所以今天要一步一步的實現上述界面及功能。

新建項目

我們來在最新版的 Android Studio 中,新建一個 module ,項目類型選第一個,帶默認 FloatingActionButton 的這個。

來看看默認的 xml 佈局的樣子:

activity_main

佈局文件的名字仍然是讓人熟悉的 activity_main ,不過港真…裏面這些組件的名字也許有的是你第一次才見到,不過沒關係,我們一會來一個個的學習下它們,在此之前呢,來看看通過 include 引入的這個佈局 content_main

content_main

這個就好眼熟了對吧,以前我們創建一個 empty activity 時,這個佈局就是 activity_main,現在它作爲子佈局,被 include 進入了現在的 MainActivity 的佈局中,這裏想提一下,其實 include 標籤是可以作爲佈局優化的一種方式,能讓你的代碼更整潔,便於管理。

現在運行一下項目,看看整體的樣子如何:

Wiget Demo

如果你的公司項目上面的標題欄部分還在手工寫,那未免也太跟不上時代了,原生的如此美觀,體驗也如巧克力入口一般絲滑,所以趕緊換成原生的吧~

組件介紹

回過頭來看看新建項目中的我們可能還不認識的組件,我來給大家做一個簡略的介紹。

CoordinatorLayout

CoordinatorLayout 是一個頂層佈局,繼承自 ViewGroup ,並且它可以通過 Behavior 來控制子 View 的各種狀態,來實現炫酷的效果,如果未來你想用 MD 的風格來設計你的 app ,CoordinatorLayout 是你必須要接觸的。

CoordinatorLayout介紹及使用–張興業

AppBarLayout

AppBarLayout 是 MD 設計中,作爲頂頭 Bar 的父佈局出現的,它的存在可以實現多種炫酷的效果,這裏不再詳細描述,需要使用自行查詢。

Toolbar

Toolbar 本身是代替 ActionBar 出現的控件,具有更靈活,可定製性更強的屬性,如果你的 app 需要一個導航欄,那目前 Toolbar 就是不二之選,Toolbar 也是我們今天的主角之一。

搭建 Toolbar

千里之行,始於足下,我們最先來搭建 Toolbar 好了。

在此之前一定要記住,如果想使用這些組件並且向下兼容它們,要在 gradle 文件中引入兩個必要的庫:

    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.android.support:design:24.2.0'

效果很簡單,來看看gif圖:

搭建Toolbar

首先我們在 layout 文件夾下 新建一個 xml 文件,名字叫:common_toolbar

代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:toolbar="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    toolbar:title="@string/author_name"
    toolbar:navigationIcon="@mipmap/ic_toolbar_navigation"
    app:popupTheme="@style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>

接下來解釋一下屬性
爲了防止我們設置 toolbar 的屬性無效,需要加上自定義的命名控件:

xmlns:toolbar="http://schemas.android.com/apk/res-auto"

這樣在 xml 中設置 toolbar:title toolbar:navigationIcon 等纔會生效(這是一個無愛的 bug)

toolbar:title 是上面的 Melo 字樣,代表 Toolbar 的標題
toolbar:navigationIcon 是 Melo 左側的抽屜按鈕,一會我們通過它來點開抽屜

接下來配置 Toolbar 右側三個點的菜單
在 menu 文件夾下 創建 menu_main.xml,代碼如下:

<menu 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"
    tools:context="com.melo.blog.wigetdemo.MainActivity">
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="1"
        android:title="@string/action_settings"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_about"
        android:orderInCategory="2"
        android:title="@string/action_about"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_share"
        android:orderInCategory="3"
        android:title="@string/action_share"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_like"
        android:orderInCategory="4"
        android:title="@string/action_like"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_collect"
        android:orderInCategory="5"
        android:title="@string/action_collect"
        app:showAsAction="never" />

</menu>

這個沒什麼太多介紹的,不懂的屬性自行查詢一下就可以解了。
將 Toolbar include 進 activity_main 的佈局中:

include

接着 MainActivity 中尋找 Toolbar ,並且爲右上方菜單設置點擊事件:

package com.melo.blog.wigetdemo;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements Toolbar.OnMenuItemClickListener {

    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
        initListener();
    }

    private void initView() {
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.inflateMenu(R.menu.menu_main);
    }

    private void initListener() {
        toolbar.setOnMenuItemClickListener(this);
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case R.id.action_settings:
                Toast.makeText(this, getResources().getString(R.string.action_settings), Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_about:
                Toast.makeText(this, getResources().getString(R.string.action_about), Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_collect:
                Toast.makeText(this, getResources().getString(R.string.action_collect), Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_like:
                Toast.makeText(this, getResources().getString(R.string.action_like), Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_share:
                Toast.makeText(this, getResources().getString(R.string.action_share), Toast.LENGTH_SHORT).show();
                break;
        }
        return false;
    }
}

是不是很簡單清晰呢?我們關於 Toolbar 來總結幾點需要注意的地方:

  • 自定義 xmlns:toolbar 否則在 xml 設置屬性會失效。
  • 菜單項的條目背景和顏色,均可以在 app:popupTheme="@style/AppTheme.PopupOverlay" style中設置:
    菜單配置
  • MainActivity 的主題應該爲 AppTheme.NoActionBar,或者在代碼中動態地調用 supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
  • 關於 Toolbar 的屬性還有很多,並且都可定製化(顏色或者大小),如果有需要你甚至可以在上面添加你的自定義 View ,如有需要,請留言或者查閱文檔。

搭建 DrawerLayout

DrawerLayout 是 Google 推出的官方組件,用來實現側滑欄抽屜的效果:

DrawerLayout

相信非常多的人已經熟悉 DrawerLayout 的使用了,我們應該注意以下兩點:

1.DrawerLayout 的第一個子 View 必須是當抽屜沒有打開時候的默認佈局。

<?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"
    android:fitsSystemWindows="true"
    tools:context="com.melo.blog.wigetdemo.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="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

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

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

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

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

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

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

在我的 Demo 中,CoordinatorLayout 是 DrawerLayout 的第一個字 View ,來作爲默認的沒有拉開抽屜時候的默認佈局。假設我用 DrawerLayout 來嵌套 content_main 時,content_main 就作爲了 DrawerLayout 未拉開的默認佈局,此時抽屜應該是在 Toolbar 之下拉出的。

2.第二點需要注意就是 抽屜的拉出方向,是由 DrawerLayout 本身的頂層佈局的 layout_gravity 屬性設置的,start就是左側拉出,end就是右側拉出,這個佈局我起名爲 common_drawer ,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/navigation_drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="#ffffff"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:background="@mipmap/drawer_header">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_margin="@dimen/fab_margin"
            android:text="DrawerHeader"
            android:textColor="@color/author_text_color"
            android:textSize="@dimen/author_text_size" />

    </FrameLayout>

</LinearLayout>

最後我將這個佈局在 activity_main 中 include 引入。
當然,我們是比較關心 DrawerLayout 和 Toolbar 設置的 navigation 按鈕 icon 是如何建立關聯的,其實很簡單,在 代碼中調用這行代碼:

ActionBarDrawerToggle mToggle = new ActionBarDrawerToggle(this,drawerlayout,toolbar, R.string.open,R.string.close);

然後在 onPostCreate 方法中 調用 mToggle.syncState() 來同步滑動狀態。
另外想多提一句,NavigationDrawer 是 google 規範的 抽屜內容的佈局,不過定製性比較差,並不建議你項目中使用它。
當然有關 DrawerLayout 還有很多屬性可以配置,有其他需要就去查查官方文檔吧~

我準備再開一個坑,就是爭取慢慢熟悉所有 MD 風格的組件,每一個都能寫 Demo 來練練手,喜歡就關注下好了。項目的 Github 地址如下:

WigetDemo–Melo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章