本模塊共有六篇文章龟糕,參考郭神的《第一行代碼》,對Material Design的學習做一個詳細的筆記换途,大家可以一起交流一下:
- Material Design 實戰(zhàn) 之第一彈——Toolbar(即本文)
- Material Design 實戰(zhàn) 之第二彈——滑動菜單詳解&實戰(zhàn)
- Material Design 實戰(zhàn) 之第三彈—— 懸浮按鈕和可交互提示(FloatingActionButton & Snackbar & CoordinatorLayout)
- Material Design 實戰(zhàn) 之第四彈 —— 卡片布局以及靈動的標題欄(CardView & AppBarLayout)
- Material Design 實戰(zhàn) 之第五彈 —— 下拉刷新(SwipeRefreshLayout)
- Material Design 實戰(zhàn) 之 第六彈 —— 可折疊式標題欄(CollapsingToolbarLayout) & 系統(tǒng)差異型的功能實現(xiàn)(充分利用系統(tǒng)狀態(tài)欄空間)
文章提要與總結(jié)
1. DrawerLayout
控件用處:實現(xiàn)滑動菜單
1.1 首先它是一個布局,在布局中允許放入兩個直接子控件,
第一個子控件是主屏幕中顯示的內(nèi)容踏兜;
第二個子控件是滑動菜單中顯示的內(nèi)容;
關(guān)于第二個子控件有一點需要注意八秃,layout_gravity這個屬性是必須指定的:left right start
1.2 添加導(dǎo)航按鈕:
1.2.1 首先調(diào)用findViewById()方法得到了DrawerLayout的實例碱妆;
1.2.2 getSupportActionBar()方法得到了ActionBar的實例;
1.2.3 調(diào)用ActionBar的setDisplayHomeAsUpEnabled()讓導(dǎo)航按鈕顯示出來昔驱;
1.2.4 調(diào)用了setHomeAsUpIndicator()方法來設(shè)置一個導(dǎo)航按鈕圖標疹尾;
1.2.5 在onOptionsItemSelected()中對HomeAsUp按鈕的點擊事件進行處理——調(diào)用DrawerLayout的openDrawer()方法將滑動菜單展示出來;
注意openDrawer()方法要求傳入一個Gravity參數(shù),
為了保證這里的行為和XML中(DrawerLayout標簽下的第二個直接子控件的android:layout_gravity值)定義的一致纳本,
我們傳入了GravityCompat.START窍蓝;
1.2.6 實際上Toolbar最左側(cè)的這個按鈕就叫作HomeAsUp按鈕,它默認的圖標是一個返回的箭頭繁成,含義是返回上一個活動吓笙;
這里將其換了圖標,并將邏輯響應(yīng)修改了巾腕;
HomeAsUp按鈕的id永遠都是android.R.id.homeC婢Α!尊搬!
2. NavigationView
控件用處:輕松布局華麗炫酷的滑動菜單頁面侮穿;
2.1 添加了兩行依賴關(guān)系
compile 'com.android.support:design:24.2.1'
compile 'de.hdodenhof:circleimageview:2.1.0'
2.2
在開始使用NavigationView之前,我們還需要提前準備好兩個東西:menu和headerLayout毁嗦。
2.2.1 menu是用來在NavigationView中顯示具體的菜單項的亲茅;
為Menu resource file;
在<menu>中嵌套了一個<group>標簽
<group>標簽下的<item>:
android:id屬性指定菜單項的id狗准,
android:icon屬性指定菜單項的圖標克锣,
android:title屬性指定菜單項顯示的文字。
2.2.2 headerLayout則是用來在NavigationView中顯示頭部布局的腔长。
為Layout resourcefile袭祟;
2.3 使用NavigationView
添加android.support.design.widget.NavigationView標簽,
使用app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"
將menu和headerLayout設(shè)置完畢
效果圖:正文
DrawerLayout /美 [?dr??] /
關(guān)于滑動菜單和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"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="This is menu"
android:textSize="30sp"
android:background="#FFF"/>
</android.support.v4.widget.DrawerLayout>
可見這里最外層的控件使用了DrawerLayout巾乳,這個控件是由support-v4庫提供的。
DrawerLayout中放置了兩個直接子控件:
第一個子控件是FrameLayout鸟召,用于作為主屏幕中顯示的內(nèi)容胆绊,當然里面還有我們剛剛定義的Toolbar。
第二個子控件這里使用了一個TextView欧募,用于作為滑動菜單中顯示的內(nèi)容压状,其實使用什么都可以,DrawerLayout并沒有限制只能使用固定的控件跟继。
但是關(guān)于第二個子控件有一點需要注意种冬,layout_gravity這個屬性是必須指定的,
因為我們需要告訴DrawerLayout滑動菜單是在屏幕的左邊還是右邊舔糖,
指定left表示滑動菜單在左邊娱两;
指定right表示滑動菜單在右邊;
這里指定了start金吗,表示會根據(jù)系統(tǒng)語言進行判斷十兢,如果系統(tǒng)語言是從左往右的趣竣,比如英語、漢語纪挎,滑動菜單就在左邊,如果系統(tǒng)語言是從右往左的跟匆,比如阿拉伯語异袄,滑動菜單就在右邊。
現(xiàn)在重新運行一下程序玛臂,然后在屏幕的左側(cè)邊緣向右拖動烤蜕,就可以讓滑動菜單顯示出來了,如圖:
這里我們并沒有改動多少代碼迹冤,
- 首先調(diào)用findViewById()方法得到了DrawerLayout的實例讽营,
- 然后調(diào)用getSupportActionBar()方法得到了ActionBar的實例,雖然這個ActionBar的具體實現(xiàn)是由Toolbar來完成的泡徙。
- 接著調(diào)用ActionBar的setDisplayHomeAsUpEnabled()方法讓導(dǎo)航按鈕顯示出來橱鹏,
- 又調(diào)用了setHomeAsUpIndicator()方法來設(shè)置一個導(dǎo)航按鈕圖標。
實際上堪藐,Toolbar最左側(cè)的這個按鈕就叫作HomeAsUp按鈕莉兰,它默認的圖標是一個返回的箭頭,含義是返回上一個活動礁竞。很明顯糖荒,這里我們將它默認的樣式(該按鈕圖標)和作用(改/設(shè)置了按鈕點擊事件)都進行了修改。
接下來在onOptionsItemSelected()方法中對HomeAsUp按鈕的點擊事件進行處理模捂,
HomeAsUp按鈕的id永遠都是android.R.id.home捶朵;
切記是android.R.id.home,如果寫成R.id.home是實現(xiàn)不了功能的狂男!
然后調(diào)用DrawerLayout的openDrawer()方法將滑動菜單展示出來综看;
注意openDrawer()方法要求傳入一個Gravity參數(shù),為了保證這里的行為和XML中定義的一致岖食,我們傳入了GravityCompat.START寓搬;
當前MainActivity全文:
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true);//讓導(dǎo)航按鈕顯示出來
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);//設(shè)置一個導(dǎo)航按鈕圖標
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.backup:
Toast.makeText(this,"You clicked Backup" , Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this,"You clicked Delete" , Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this,"You clicked Settings" , Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
}
運行程序,效果如下:
可見在Toolbar的最左邊出現(xiàn)了一個導(dǎo)航按鈕县耽,用戶看到這個按鈕就知道這肯定是可以點擊的句喷。
現(xiàn)在點擊一下這個按鈕,滑動菜單界面就會再次展示出來了兔毙。
NavigationView
首先這個控件是DesignSupport庫中提供的唾琼,需要將這個庫引入到項目中。
打開app/build.gradle文件澎剥,在dependencies閉包中添加依賴:
compile 'com.android.support:design:24.2.1'
compile 'de.hdodenhof:circleimageview:2.1.0'
這里添加了兩行依賴關(guān)系锡溯,
第一行就是DesignSupport庫,
第二行是一個開源項目CircleImageView,它可以用來輕松實現(xiàn)圖片圓形化的功能祭饭,我們待會就會用到它芜茵。
CircleImageView的項目主頁地址是:https://github.com/hdodenhof/CircleImageView。
3>糯!
在開始使用NavigationView之前寺鸥,我們還需要提前準備好兩個東西:menu和headerLayout猪钮。
menu是用來在NavigationView中顯示具體的菜單項的;
headerLayout則是用來在NavigationView中顯示頭部布局的胆建。
1/4.準備menu
我們先來準備menu烤低,這里我事先找了幾張圖片來作為按鈕的圖標,并將它們放在了drawable-xxhdpi目錄下笆载。然后右擊menu文件夾→New→Menu resource file扑馁,創(chuàng)建一個nav_menu.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_call"
android:icon="@drawable/nav_call"
android:title="Call"/>
<item
android:id="@+id/nav_friends"
android:icon="@drawable/nav_friends"
android:title="Friends"/>
<item
android:id="@+id/nav_location"
android:icon="@drawable/nav_location"
android:title="Location"/>
<item
android:id="@+id/nav_mail"
android:icon="@drawable/nav_mail"
android:title="Mail"/>
<item
android:id="@+id/nav_task"
android:icon="@drawable/nav_task"
android:title="Tasks"/>
</group>
</menu>
然后將group的checkableBehavior屬性指定為singlegroup表示一個組檐蚜,
checkableBehavior指定為single表示組中的所有菜單項只能單選;
那么下面我們來看一下這些菜單項吧沿侈。這里一共定義了5個item闯第,
分別使用
android:id屬性指定菜單項的id,
android:icon屬性指定菜單項的圖標缀拭,
android:title屬性指定菜單項顯示的文字咳短。
就是這么簡單,現(xiàn)在我們已經(jīng)把menu準備好了蛛淋。
2/4.準備headerLayout
接下來應(yīng)該準備headerLayout了咙好,這是一個可以隨意定制的布局,不過這里不將它做得太復(fù)雜褐荷。我們就在headerLayout中放置頭像勾效、用戶名、郵箱地址這3項內(nèi)容吧叛甫;
說到頭像层宫,那我們還需要再準備一張圖片,這里找了一張寵物圖片其监,并把它放在了drawable-xxhdpi目錄下萌腿。
另外這張圖片最好是一張正方形圖片,因為待會我們會把它圓形化抖苦。
然后右擊layout文件夾→New→Layout resourcefile毁菱,創(chuàng)建一個nav_header.xml文件米死。
修改其中的代碼,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:padding="10dp"
android:background="?attr/colorPrimary">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/icon_image"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="@drawable/nav_icon"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/mail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="8267*****@qq.com"
android:textColor="#FFF"
android:textSize="14sp"/>
<TextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/mail"
android:text="wanchuangxiaoyun"
android:textColor="#FFF"
android:textSize="14sp"/>
</RelativeLayout>
可以看到贮庞,布局文件的最外層是一個RelativeLayout峦筒,我們將它的
寬度設(shè)為match_parent,
高度設(shè)為180dp窗慎,
這是一個NavigationView比較適合的高度物喷,然后
指定它的背景色為colorPrimary;
在RelativeLayout中我們放置了3個控件捉邢,
CircleImageView是一個用于將圖片圓形化的控件脯丝,它的用法非常簡單商膊,基本和ImageView是完全一樣的伏伐,這里給它指定了一張圖片作為頭像,然后設(shè)置為居中顯示晕拆。
另外兩個TextView分別用于顯示用戶名和郵箱地址藐翎,它們都用到了一些RelativeLayout的定位屬性;
3/4.使用NavigationView
現(xiàn)在menu和headerLayout都準備好了实幕,我們終于可以使用NavigationView了吝镣。
修改activitymam.xml中的代碼,如下所示:
<?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"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
可見這里將之前的TextView換成了NavigationView昆庇,這樣滑動菜單中顯示的內(nèi)容也就變成NavigationView了末贾。
這里又通過app:menu和app:headerLayout將我們剛才準備好的menu和headerLayout設(shè)置了進去,
android:layout_gravity="start"則是跟上面的textview一個道理了整吆,用于指明滑動菜單的滑動位置拱撵,
這樣NavigationView就定義完成了。
接下來還要去處理菜單項的點擊事件表蝙。修改MainActivity中的代碼:
代碼還是比較簡單的拴测,
這里首先獲取到了NavigauonView的實例,
然后調(diào)用它的setCheckedItem()方法將Call菜單項設(shè)置為默認選中府蛇。
接著調(diào)用了setNavigationItemSelectedListener()方法來設(shè)置一個菜單項選中事件的監(jiān)聽器集索,當用戶點擊了任意菜單項時,就會回調(diào)到onNavigationItemSelected()方法中汇跨。
我們可以在這個方法中寫相應(yīng)的邏輯處理务荆,不過這里并沒有附加任何邏輯,只是調(diào)用了DrawerLayout的closeDrawers()方法將滑動菜單關(guān)閉穷遂,這也是合情合理的做法蛹含。
下面是當前MainActivity.java的全文:
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navView = (NavigationView) findViewById(R.id.nav_view);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true);//讓導(dǎo)航按鈕顯示出來
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);//設(shè)置一個導(dǎo)航按鈕圖標
}
navView.setCheckedItem(R.id.nav_call);//將Call菜單項設(shè)置為默認選中
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener(){
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
mDrawerLayout.closeDrawers();//關(guān)閉滑動菜單
return true;
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.backup:
Toast.makeText(this,"You clicked Backup" , Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this,"You clicked Delete" , Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this,"You clicked Settings" , Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
}
現(xiàn)在可以重新運行一下程序了塞颁,點擊一下Toolbar左側(cè)的導(dǎo)航按鈕浦箱,效果如圖所示:
怎么樣吸耿?這樣的滑動菜單頁面,你無論如何也不能說它丑了吧酷窥?MaterialDesign的魅力就在
這里咽安,它真的是一種非常美觀的設(shè)計理念,只要你按照它的各種規(guī)范和建議來設(shè)計界面蓬推,最終做
出來的程序就是特別好看的妆棒。——郭霖大神