本文原創,轉載請註明出處。
寫在前面:
因爲剛剛畢業不久,面對編程世界中快速的知識更迭、龐大的知識體系,總覺得有心無力。想學的東西很多,想實踐的技術很多,但是感覺始終處在追追趕趕的狀態中。終於到了週末,拿出來這非常難得的大塊時間,做一次知識總結和技術實踐。
最近公司在重構代碼,包括UI佈局這塊也是,打算採用 DrawerLayout + Toolbar + Statusbar 這種形式展示出來。說來慚愧,其實這三個組件出來很久了,也看過一些資料,不過忘記是從哪裏看到過一句話,那就是“沒有敲過的代碼永遠不屬於自己,並且也不要指望能找到一行都不需要修改的代碼”,我非常認同這句話,所以今天要一步一步的實現上述界面及功能。
新建項目
我們來在最新版的 Android Studio 中,新建一個 module ,項目類型選第一個,帶默認 FloatingActionButton 的這個。
來看看默認的 xml 佈局的樣子:
佈局文件的名字仍然是讓人熟悉的 activity_main ,不過港真…裏面這些組件的名字也許有的是你第一次才見到,不過沒關係,我們一會來一個個的學習下它們,在此之前呢,來看看通過 include 引入的這個佈局 content_main 。
這個就好眼熟了對吧,以前我們創建一個 empty activity 時,這個佈局就是 activity_main,現在它作爲子佈局,被 include 進入了現在的 MainActivity 的佈局中,這裏想提一下,其實 include 標籤是可以作爲佈局優化的一種方式,能讓你的代碼更整潔,便於管理。
現在運行一下項目,看看整體的樣子如何:
如果你的公司項目上面的標題欄部分還在手工寫,那未免也太跟不上時代了,原生的如此美觀,體驗也如巧克力入口一般絲滑,所以趕緊換成原生的吧~
組件介紹
回過頭來看看新建項目中的我們可能還不認識的組件,我來給大家做一個簡略的介紹。
CoordinatorLayout
CoordinatorLayout 是一個頂層佈局,繼承自 ViewGroup ,並且它可以通過 Behavior 來控制子 View 的各種狀態,來實現炫酷的效果,如果未來你想用 MD 的風格來設計你的 app ,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圖:
首先我們在 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 的佈局中:
接着 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 的使用了,我們應該注意以下兩點:
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 地址如下: