第十二章主要講了 Material Design 的一些用法
一、Maternal Design 介紹
??Android 平臺(tái)的界面風(fēng)格長(zhǎng)期難以統(tǒng)一违寞,為了解決這個(gè)問題纵潦,Google 推出了全新的界面設(shè)計(jì)語(yǔ)言--Material Design.
??從 Android5.0開始,就將所有內(nèi)置的應(yīng)用都使用 Material Design 風(fēng)格來(lái)進(jìn)行設(shè)計(jì)听绳。谷歌在2015年 Google I/O 大會(huì)上推出了 Design Support 庫(kù)颂碘。
二、Toolbar
??每個(gè)活動(dòng)最頂部的那個(gè)標(biāo)題欄其實(shí)就是 ActionBar椅挣,不過(guò) ActionBar 由于其設(shè)計(jì)原因头岔,被限定只能位于活動(dòng)頂部,從而不能實(shí)現(xiàn)一些 Material Design 的效果鼠证,因此官方已經(jīng)不再建議使用 ActionBar 了峡竣。
??ToolBar 的強(qiáng)大之處在于,它不僅繼承了 ActionBar 的所有功能名惩,而且靈活性很高澎胡,可以配合其他控件一起來(lái)完成一些 Material Design 的效果。
注意:任何一個(gè)新建的項(xiàng)目娩鹉,默認(rèn)都會(huì)顯示 ActionBar 的攻谁,這個(gè) ActionBar 是根據(jù)項(xiàng)目中指定的主題來(lái)顯示的。打開清單文件弯予,找到 <application>標(biāo)簽中有一個(gè) android:theme 屬性戚宦,并且指定了一個(gè) AppTheme 主題。
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
??這個(gè) DarkActionBar 就是一個(gè)深色的 ActionBar 主題锈嫩,項(xiàng)目中自帶的 ActionBar 就是因?yàn)橹付诉@個(gè)主題才出現(xiàn)的受楼。但是我們現(xiàn)在要使用 ToolBar,所以要指定一個(gè)不帶 ActionBar 的主題呼寸,通常有 Theme.AppCompat.NoActionBar 和 Theme.AppCompat.Light.NoActionBar 這兩種主題
艳汽,其中 Theme.AppCompat.NoActionBar 表示深色主題,他會(huì)將界面的主體顏色設(shè)置成深色对雪,陪襯顏色設(shè)成淡色河狐。而 Theme.AppCompat.Light.NoActionBar 表示淡色主題,它會(huì)將界面的主體顏色設(shè)置成淡色瑟捣,陪襯顏色設(shè)成深色馋艺。
??觀察一下 AppTheme 中的屬性重寫,這里重寫了 colorPrimary迈套、colorPrimaryDark 和 colorAccent 這3個(gè)屬性的顏色捐祠。
其他:
- 1.colorPrimary:應(yīng)用的主要色調(diào),actionBar默認(rèn)使用該顏色桑李,Toolbar導(dǎo)航欄的底色
- 2.colorPrimaryDark:應(yīng)用的主要暗色調(diào)踱蛀,statusBarColor默認(rèn)使用該顏色
- 3.statusBarColor:狀態(tài)欄顏色窿给,默認(rèn)使用colorPrimaryDark
- 4.windowBackground:窗口背景顏色
- 5.navigationBarColor:底部欄顏色
- 6.colorForeground:應(yīng)用的前景色,ListView的分割線星岗,switch滑動(dòng)區(qū)默認(rèn)使用該顏色
- 7.colorBackground:應(yīng)用的背景色填大,popMenu的背景默認(rèn)使用該顏色
- 8.colorAccent:CheckBox,RadioButton俏橘,SwitchCompat等一般控件的選中效果默認(rèn)采用該顏色
- 9.colorControlNormal:CheckBox允华,RadioButton,SwitchCompat等默認(rèn)狀態(tài)的顏色寥掐。
- 10.colorControlHighlight:控件按壓時(shí)的色調(diào)
- 11.colorControlActivated:控件選中時(shí)的顏色靴寂,默認(rèn)使用colorAccent
- 12.colorButtonNormal:默認(rèn)按鈕的背景顏色
- 13.editTextColor:默認(rèn)EditView輸入框字體的顏色。
- 14.textColor:Button召耘,textView的文字顏色
- 15.textColorPrimaryDisableOnly:RadioButton checkbox等控件的文字
- 16.textColorPrimary:應(yīng)用的主要文字顏色百炬,actionBar的標(biāo)題文字默認(rèn)使用該顏色
- 17.colorSwitchThumbNormal:switch thumbs 默認(rèn)狀態(tài)的顏色
??使用了 NoActionBar 主題后,我們已經(jīng)將 ActionBar 隱藏起來(lái)了污它,接下來(lái)就要使用 ToolBar 代替 ActionBar 了剖踊。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<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">
</android.support.v7.widget.Toolbar>
</FrameLayout>
這里首先記得添加 xmlns:app 指定命名空間,因?yàn)?Material Design 是在 Android5.0系統(tǒng)中才出現(xiàn)的衫贬,而很多 Material 屬性在5.0之前的系統(tǒng)中并不存在德澈,為了兼容之前的老系統(tǒng),我們不能使用 android:attribute 這樣的寫法了固惯,就要使用 app:attribute 的寫法梆造。
我們使用了 ToolBar 控件,該控件是 appcompat-v7庫(kù)提供的葬毫,高度指定為 ActionBar 的高度镇辉,背景色設(shè)置為 colorPrimary。接下來(lái)贴捡,我們?cè)O(shè)置了主題忽肛,因?yàn)槲覀冊(cè)?style.xm里面將程序的主題設(shè)置成了淡色主題,因此 ToolBar 也是淡色主題烂斋,ToolBar 上的元素就會(huì)自動(dòng)使用深色主題麻裁,看起來(lái)很難看,為了讓 ToolBar 單獨(dú)使用深色主題源祈,我們就使用了 theme 為 ToolBar 單獨(dú)指定了一個(gè)主題:
ThemeOverlay.AppCompat.Dark.ActionBar
,但是這樣又會(huì)有一個(gè)問題色迂,如果 ToolBar 中有菜單按鈕香缺,彈出的菜單項(xiàng)會(huì)變成深色主題,又變得很難看歇僧,于是使用了app:popupTheme
屬性單獨(dú)將彈出的菜單指定成了淡色主題图张。
Toolbar toolBar = (Toolbar) findViewById(R.id.toolbar);
/*
這句話的作用是:既使用了 ToolBar锋拖,又讓它的外觀和功能都和 ActionBar 一致
*/
setSupportActionBar(toolBar);
<activity android:name=".MaterialDesignActivity"
android:label="Material Design">
<!--這里我們?yōu)?Activity 指定了一個(gè) label,作用就是讓在 ToolBar 中顯示標(biāo)題-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
??接下來(lái)我們給 ToolBar 添加一個(gè) action 按鈕
<?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/backup"
android:icon="@mipmap/ic_launcher"
android:title="Backup"
app:showAsAction="always" />
<item
android:id="@+id/delete"
android:icon="@mipmap/ic_launcher"
android:title="delete"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:icon="@mipmap/ic_launcher"
android:title="settings"
app:showAsAction="never" />
</menu>
<?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">
<!--使用 showAsAction 來(lái)指定按鈕的顯示位置 祸轮,
這里之所以使用 app 命名空間兽埃,是為了能夠
兼容低版本-->
<!-- always 表示永遠(yuǎn)顯示在 ToolBar 上,如果屏幕空間不夠則不顯示 -->
<item
android:id="@+id/backup"
android:icon="@mipmap/ic_launcher"
android:title="Backup"
app:showAsAction="always" />
<!--ifRoom 表示如果屏幕空間足夠就顯示在 ToolBar 上适袜,
不夠的話就顯示在菜單當(dāng)中-->
<item
android:id="@+id/delete"
android:icon="@mipmap/ic_launcher"
android:title="delete"
app:showAsAction="ifRoom" />
<!-- never 表示永遠(yuǎn)顯示在菜單當(dāng)中-->
<item
android:id="@+id/settings"
android:icon="@mipmap/ic_launcher"
android:title="settings"
app:showAsAction="never" />
</menu>
注意:ToolBar 中的 action 按鈕只會(huì)顯示圖標(biāo)柄错,菜單中的 action 按鈕只會(huì)顯示文字。
@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.backup:
Toast.makeText(this, "backUp", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "delete", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "settings", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}
ToolBar 使用總結(jié):
- 首先要設(shè)置應(yīng)用主題是 NoActionBar 的
- 然后在布局文件中要使用 app 命名空間
- 給 ToolBar 設(shè)置高度為
?attr/actionBarSize
ActionBar 的高度苦酱,背景色設(shè)置為?attr/colorPirmary
- 給 ToolBar 設(shè)置高度為
- 根據(jù)程序主體顏色售貌,設(shè)置 ToolBar 的 theme 主體顏色(與程序主體顏色相反),
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
疫萤,然后設(shè)置彈出的菜單主體顏色(與程序主體顏色相同)app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
- 根據(jù)程序主體顏色售貌,設(shè)置 ToolBar 的 theme 主體顏色(與程序主體顏色相反),
- ToolBar 最左側(cè)有一個(gè)按鈕颂跨,叫做 HomeAsUp,默認(rèn)是一個(gè)向左的箭頭扯饶,該按鈕的 id 永遠(yuǎn)都是 android.R.id.home
二恒削、DrawerLayout(滑動(dòng)菜單)
??所謂滑動(dòng)菜單,就是將一些菜單隱藏起來(lái)尾序,不放在主屏幕上钓丰,然后可以通過(guò)滑動(dòng)的方式將菜單顯示出來(lái)。我們可以借助 DrawerLayout 來(lái)實(shí)現(xiàn)這種效果蹲诀。
??首先 DrawerLayout (support.v4庫(kù)提供)是一個(gè)布局斑粱,在布局中允許放入兩個(gè)直接子控件,第一個(gè)子控件是主屏幕中顯示的內(nèi)容脯爪,第二個(gè)控件是滑動(dòng)菜單中顯示的內(nèi)容(側(cè)邊欄)则北。
<?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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 主屏幕的內(nèi)容 -->
<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">
</android.support.v7.widget.Toolbar>
</FrameLayout>
<!-- 側(cè)邊欄的內(nèi)容 -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="我是側(cè)邊欄中的 TextView"
android:textSize="30sp"
android:background="@android:color/white"/>
</android.support.v4.widget.DrawerLayout>
注意:關(guān)于第二個(gè)子控件,layout_gravity這個(gè)屬性必須指定痕慢,因?yàn)槲覀冃枰嬖V DrawerLayout 滑動(dòng)菜單是在屏幕的左邊還是右邊尚揣,這里指定了 start,表示根據(jù)系統(tǒng)語(yǔ)言進(jìn)行判定掖举,如果系統(tǒng)語(yǔ)言是從左往右的快骗,比如英語(yǔ)、漢語(yǔ)塔次,滑動(dòng)菜單就是在左邊方篮,如果系統(tǒng)語(yǔ)言是從右往左的,比如阿拉伯語(yǔ)励负,滑動(dòng)菜單就是在右邊藕溅。
??這時(shí)候會(huì)有點(diǎn)問題,可能用戶不知道可以滑動(dòng)继榆,不知道有側(cè)邊欄這個(gè)東西巾表,Material Design 建議的做法是在 Toolbar 的左邊加入一個(gè)導(dǎo)航按鈕汁掠,點(diǎn)擊按鈕就將側(cè)邊欄展示出來(lái)。
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
/*
通過(guò) getSupportActionBar()方法獲取 ActionBar集币,雖然是 ActionBar考阱,
但是其實(shí)具體實(shí)現(xiàn)是由 ToolBar 來(lái)實(shí)現(xiàn)的
*/
ActionBar actionBar = getSupportActionBar();
/*
這里注意,其實(shí) ToolBar 最左側(cè)的導(dǎo)航按鈕就叫做 HomeAsUp 按鈕
他默認(rèn)的是一個(gè)返回箭頭鞠苟,我們修改了他的樣式
*/
if(actionBar != null){
//讓導(dǎo)航按鈕顯示出來(lái)
actionBar.setDisplayHomeAsUpEnabled(true);
//設(shè)置導(dǎo)航按鈕圖標(biāo)
actionBar.setHomeAsUpIndicator(R.mipmap.ic_launcher);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.backup:
Toast.makeText(this, "backUp", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "delete", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "settings", Toast.LENGTH_SHORT).show();
break;
case android.R.id.home:
/*
注意:這里乞榨,HomeAsUp 按鈕的 id 永遠(yuǎn)都是 android.R.id.home
*/
drawerLayout.openDrawer(GravityCompat.START);
break;
default:
break;
}
return true;
}
DrawerLayout 使用總結(jié):
- DrawerLayout 是一個(gè)布局,并且允許放入兩個(gè)直接子控件偶妖,第一個(gè)控件是主屏幕中顯示的內(nèi)容姜凄,第二個(gè)控件是滑動(dòng)菜單中顯示的內(nèi)容。
- 第二個(gè)控件必須制定 layout_gravity 屬性趾访,用于告訴 DrawerLayout 是從哪個(gè)方向滑動(dòng)出來(lái)的态秧。
三、NavigationView
??NavigationView 是 Design Support 庫(kù)中提供的一個(gè)控件扼鞋,所以我們需要引入這個(gè)庫(kù)申鱼,而且在使用 NavigationView 之前,我們需要提前準(zhǔn)備好兩個(gè)東西:menu 和 headerLayout云头,menu 是用來(lái)在 NavigationView 中顯示具體的菜單項(xiàng)的捐友,headerLayout 則是用來(lái)在 NavigationView 中顯示頭布局的。
//design 庫(kù)
compile 'com.android.support:design:24.2.1'
//circleimageview
compile 'de.hdodenhof:circleimageview:2.1.0'
??CircleImageView 可以用來(lái)輕松實(shí)現(xiàn)圖片圓形化的功能溃槐,項(xiàng)目主頁(yè)地址是:https://github.com/hdodenhof/CircleImageView
??在開始使用 NavigationView 之前匣砖,我們還需要提前準(zhǔn)備好兩個(gè)東西:menu 和 headerLayout,其中 menu 是用來(lái)在 NavigationView 中顯示具體的菜單項(xiàng)的昏滴, headerLayout 則是用來(lái)在顯示頭部布局的猴鲫。
??接下來(lái)在 menu 文件夾中創(chuàng)建一個(gè) xml 文件,叫做nav_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- group表示一個(gè)組谣殊,checkableBehavior屬性指定為single表示組中所有菜單項(xiàng)只能單選 -->
<group android:checkableBehavior="single">
<item android:id="@+id/nav_call"
android:icon="@mipmap/ic_launcher"
android:title="Call" />
<item android:id="@+id/nav_friends"
android:icon="@mipmap/ic_launcher"
android:title="Friends" />
<item android:id="@+id/nav_location"
android:icon="@mipmap/ic_launcher"
android:title="Location" />
<item android:id="@+id/nav_mail"
android:icon="@mipmap/ic_launcher"
android:title="Mail" />
<item android:id="@+id/nav_task"
android:icon="@mipmap/ic_launcher"
android:title="Task" />
</group>
</menu>
??然后我們?cè)?layout 文件夾中創(chuàng)建一個(gè) xml 文件拂共,命名為:nav_header.xml
。
<?xml version="1.0" encoding="utf-8"?>
<!-- 這里寬度設(shè)為match_parent姻几,高度設(shè)為180dp宜狐,這是一個(gè) NavigationView 比較合適的高度 -->
<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"
android:orientation="vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/icon_img"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerInParent="true"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/mail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="www.baidu.com@game.com"
android:textColor="#ffffff"
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="Tony"
android:textColor="#ffffff"
android:textSize="14sp"/>
</RelativeLayout>
??然后修改 Activity 的 layout 布局文件
<?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">
<!-- 主布局 -->
<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">
</android.support.v7.widget.Toolbar>
</FrameLayout>
<!-- 側(cè)邊欄 -->
<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:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu">
<!-- 這里通過(guò) app:header 和 app:menu 屬性將我們剛才準(zhǔn)備好的
menu 和 headerLayout 設(shè)置拉進(jìn)去 -->
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
navView = (NavigationView) findViewById(R.id.nav_view);
//設(shè)置默認(rèn)選中的菜單項(xiàng)
navView.setCheckedItem(R.id.nav_call);
//菜單項(xiàng)選中事件監(jiān)聽
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
drawerLayout.closeDrawers();
return true;
}
});
NavigationView使用總結(jié):
- 1.使用 NavigationView 需要引入design 庫(kù)。
- 2.還需要準(zhǔn)備兩個(gè) xml 文件:展示 menu 的 xml 文件蛇捌,和展示頭部 header 的 xml 文件抚恒。
- 3.頭部的 header 的 xml 布局文件中,最外層根布局高度設(shè)置為180dp络拌,這是一個(gè)比較適合 NavigationView 的高度柑爸。
- 4.然后通過(guò)
app:menu 和 app:headerLayout
屬性來(lái)指定文件。
四盒音、FloatingActionButton (懸浮按鈕)
??這是 Design Support 庫(kù)中提供的一個(gè)控件表鳍,默認(rèn)使用 colorAccent 來(lái)作為按鈕的顏色。
<?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/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">
</android.support.v7.widget.Toolbar>
<!-- 懸浮按鈕 -->
<!-- 這里 end 和 start 一樣祥诽,如果系統(tǒng)語(yǔ)言是從左往右的譬圣,那么 end
就在右邊,如果系統(tǒng)語(yǔ)言是從右往左的雄坪,那么 end 就在左邊厘熟。
可以使用 app:elevation 屬性來(lái)給按鈕指定一個(gè)高度值,高度值
越大维哈,投影范圍也越大绳姨,但是投影效果越淡,高度值越小阔挠,投影范圍
也越小飘庄,投影效果越濃 -->
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:elevation="8dp"/>
</FrameLayout>
<!-- 側(cè)邊欄 -->
<!-- ...... -->
</android.support.v4.widget.DrawerLayout>
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ThirdActivity.this, "點(diǎn)擊了懸浮按鈕", Toast.LENGTH_SHORT).show();
}
});
五、Snackbar
??還是由 Design Support 庫(kù)提供的购撼。但是需要明確一點(diǎn)跪削,Snackbar 并不是 Toast 的替代品,他們兩者之間有著不同的應(yīng)用場(chǎng)景迂求。Toast 的作用是告訴用戶現(xiàn)在發(fā)生了什么事情碾盐,用戶只能被動(dòng)接受。而 Snackbar 則在這方面進(jìn)行了擴(kuò)展揩局,它允許在提示當(dāng)中加入一個(gè)可交互按鈕毫玖,當(dāng)用戶點(diǎn)擊按鈕的時(shí)候可以執(zhí)行一些額外的操作邏輯。
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Toast.makeText(ThirdActivity.this, "點(diǎn)擊了懸浮按鈕", Toast.LENGTH_SHORT).show();
//使用 Snackbar
/*
Snackbar 使用 make 方法來(lái)創(chuàng)建
參1:傳入一個(gè) View 對(duì)象凌盯,只要是當(dāng)前界面任意一個(gè) View 都可以付枫,Snackbar 會(huì)使用
這個(gè) View 來(lái)自動(dòng)查找最外層的布局,用于展示Snackbar
參2:Snackbar 中顯示的內(nèi)容
參3:Snackbar 顯示的時(shí)長(zhǎng)
*/
Snackbar.make(v,"是你點(diǎn)擊了懸浮按鈕十气?",Snackbar.LENGTH_SHORT)
//通過(guò) setAction 方法設(shè)置一個(gè)動(dòng)作
.setAction("Yes", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ThirdActivity.this, "是我點(diǎn)擊了", Toast.LENGTH_SHORT).show();
}
//調(diào)用 show() 方法讓 Snackbar 顯示出來(lái)
}).show();
}
});
??不管是點(diǎn)擊 YES 還是過(guò)一段時(shí)間等待 Snackbar 自動(dòng)消失励背,Snackbar都是自帶動(dòng)畫效果的,但是你會(huì)發(fā)現(xiàn)一個(gè)問題砸西,就是 Snackbar 將我們的 FloatingActionBar 給擋住了叶眉,這就需要借助 CoordinatorLayout 就行了。
六芹枷、CoordinatorLayout
??CoordinatorLayout 可以說(shuō)是一個(gè)加強(qiáng)版的 FrameLayout衅疙,該布局也是由 Design Support 庫(kù)提供的,在普通情況下和 FrameLayout 基本一致鸳慈。
??事實(shí)上饱溢,CoordinatorLayout 可以監(jiān)聽其所有子控件的各種事件,然后自動(dòng)幫我們做出最為合理的響應(yīng)走芋,舉個(gè)例子:剛才彈出的 Snackbar 將懸浮按鈕擋住了绩郎,如果我們讓 CoordinatorLayout 監(jiān)聽到 Snackbar 的彈出事件潘鲫,那么它會(huì)自動(dòng)將內(nèi)部的 FloatingActionButton 向上偏移,從而確保不會(huì)被 Snackbar 擋住肋杖。
<?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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 主布局 -->
<android.support.design.widget.CoordinatorLayout
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">
</android.support.v7.widget.Toolbar>
<!-- 懸浮按鈕 -->
<!-- 這里 end 和 start 一樣溉仑,如果系統(tǒng)語(yǔ)言是從左往右的,那么 end
就在右邊状植,如果系統(tǒng)語(yǔ)言是從右往左的浊竟,那么 end 就在左邊。
可以使用 app:elevation 屬性來(lái)給按鈕指定一個(gè)高度值津畸,高度值
越大振定,投影范圍也越大,但是投影效果越淡肉拓,高度值越小后频,投影范圍
也越小,投影效果越濃 -->
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:elevation="8dp"/>
</android.support.design.widget.CoordinatorLayout>
<!-- 側(cè)邊欄 -->
<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:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
??問題解決了帝簇,但是有點(diǎn)奇怪徘郭,F(xiàn)loatingActionButton 是 CoordinatorLayout 的子控件沒問題,但 Snackbar 并不是丧肴,為什么 CoordinatorLayout 還會(huì)監(jiān)聽到呢残揉?
道理很簡(jiǎn)單,我們?cè)?Snackbar 的 make() 方法中傳入的第一個(gè)參數(shù)芋浮,就是用來(lái)指定 Snackbar 是基于哪個(gè) View 來(lái)觸發(fā)的抱环,我們傳入的是 FloatingActionBar,而 FloatingActionBar 又是 CoordinatorLayout 中的子控件纸巷,所以這個(gè)事件就能被監(jiān)聽到镇草,如果給 Snackbar 的 make() 方法的第一個(gè)參數(shù)傳入別的 View,比如傳入 DrawerLayout瘤旨,那么 Snackbar 就會(huì)再次遮擋懸浮按鈕梯啤,因?yàn)?DrawerLayout 不是 CoordinatorLayout 的子控件,CoordinatorLayout 也就無(wú)法堅(jiān)挺到 Snackbar 的彈出和隱藏事件了存哲。
FloatingActionBar因宇、Snackbar、CoordinatorLayout 使用總結(jié)
- 1.這三個(gè)控件都是基于 Design Support 庫(kù)中的
- 2.FloatingActionBar 可以通過(guò) android:src 屬性設(shè)置圖標(biāo)祟偷,還可以通過(guò) app:elevation 設(shè)置按鈕懸浮高度察滑,設(shè)置點(diǎn)擊事件和其他 View 的方法一樣
- 3.CoordinatorLayout 其實(shí)就是高級(jí) FrameLayout,但是它可以監(jiān)聽其所有子控件的各種事件修肠,然后自動(dòng)做出最為合理的響應(yīng)贺辰。
- 4.Snackbar 通過(guò) make 方法創(chuàng)建,通過(guò)setAction 方法設(shè)置一個(gè)動(dòng)作,可以和用戶進(jìn)行交互饲化,通過(guò) show 方法將 Snackbar 顯示出來(lái)莽鸭。
- 5.Snackbar 的 make 方法中,參1可以是當(dāng)前布局的任意一個(gè) View吃靠,如果有 FloatingActionBar 最好傳入 FloatingActionBar蒋川,然后和 CoordiantorLayout 一起使用,避免 Snackbar 擋住 FloatingActionBar撩笆。
- 6.FloatingActionBar 可以通過(guò) app:layout_anchor="@id/xxx" 屬性設(shè)置錨點(diǎn),指定懸浮按鈕出現(xiàn)在某個(gè)控件區(qū)域內(nèi)缸浦,然后使用 app:layout_anchorGravity 屬性將懸浮按鈕定位在區(qū)域內(nèi)的某個(gè)位置夕冲。
七、CardView(卡片式布局)
??CardView 由 appcompat-v7 提供裂逐,實(shí)際上 CardView 也是一個(gè) FrameLayout歹鱼,只是額外提供了圓角和陰影等效果,看上去會(huì)有立體的感覺卜高。
??我們使用一個(gè)簡(jiǎn)單的例子來(lái)展示一下 CardView 控件
<?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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 主布局 -->
<android.support.design.widget.CoordinatorLayout
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">
</android.support.v7.widget.Toolbar>
<!-- 這里添加一個(gè) RecyclerView -->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:elevation="8dp"/>
</android.support.design.widget.CoordinatorLayout>
<!-- 側(cè)邊欄 -->
<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:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
/**
* 實(shí)體類
*/
public class Fruit {
private String name;//水果的名字
private int imageId;//水果對(duì)應(yīng)資源的圖片id
public Fruit(){
}
public Fruit(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getImageId() {
return imageId;
}
public void setImageId(int imageId) {
this.imageId = imageId;
}
@Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
", imageId=" + imageId +
'}';
}
}
<!-- 這個(gè)是RecyclerView的item布局 -->
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_fruit"
android:layout_width="match_parent"
android:layout_height="100dp"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="5dp"
android:textSize="16sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
/**
* RecyclerView 的適配器
*/
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> mFruitList;
private Context mContext;
public FruitAdapter(List<Fruit> list){
this.mFruitList = list;
}
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView ivFruit;
TextView tvName;
public ViewHolder(View itemView) {
super(itemView);
ivFruit = itemView.findViewById(R.id.iv_fruit);
tvName = itemView.findViewById(R.id.tv_name);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(mContext == null){
mContext = parent.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.tvName.setText(fruit.getName());
Glide.with(mContext).load(fruit.getImageId()).into(holder.ivFruit);
}
@Override
public int getItemCount() {
return mFruitList == null ? 0 : mFruitList.size();
}
}
這里使用了 Glide 加載圖片弥姻,Glide 項(xiàng)目主頁(yè)地址是:https://github.com/bumptech/glide
這里為什么要用 Glide 而不用傳統(tǒng)的方式設(shè)置圖片呢?因?yàn)槿绻麍D片像素非常高的話掺涛,如果不進(jìn)行壓縮就直接展示庭敦,很容易就會(huì)引起內(nèi)存泄露,而 Glide 在內(nèi)部做了許多復(fù)雜的邏輯操作薪缆,其中就包括了圖片的壓縮秧廉。
//數(shù)據(jù)
private Fruit[] fruits = {
new Fruit("Apple", R.mipmap.ic_launcher),
new Fruit("Banana", R.mipmap.ic_launcher),
new Fruit("Orange", R.mipmap.ic_launcher),
new Fruit("Watermelon", R.mipmap.ic_launcher),
new Fruit("Pear", R.mipmap.ic_launcher),
new Fruit("Grape", R.mipmap.ic_launcher),
new Fruit("Pineapple", R.mipmap.ic_launcher),
new Fruit("Strawbeery", R.mipmap.ic_launcher),
new Fruit("Cherry", R.mipmap.ic_launcher),
new Fruit("Mango", R.mipmap.ic_launcher)
};
private List<Fruit> fruitList = new ArrayList<>();
initFruits();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this,2);
recyclerView.setLayoutManager(gridLayoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
private void initFruits() {
fruitList.clear();
for (int i = 0; i < 50; i++) {
Random random = new Random();
int index = random.nextInt(fruits.length);
fruitList.add(fruits[index]);
}
}
??CardView 的效果已經(jīng)出來(lái)了,但是你自己觀察一下拣帽,ToolBar 被 RecyclerView 擋住了疼电,怎么辦?這就要借助另一個(gè)工具 -- AppBarLayout了减拭。
八蔽豺、AppBarLayout
??分析下上述問題的原因,因?yàn)?ToolBar 和 RecyclerView 都放在 CoordinatorLayout 中拧粪,而 CoordinatorLayout 是一個(gè)加強(qiáng)版的 FrameLayout修陡,那么肯定會(huì)遮擋了啊。那么如果我們?cè)?CoordinatorLayout 內(nèi)既们,給 ToolBar 和 RecyclerView 的包一層 LinearLayout 或者 RelativeLayout 是不是就可以了呢濒析?是的,是可以了啥纸,但是号杏,我們既然引出了 AppBarLayout,就有用 AppBarLayout 的理由。
??AppBarLayout 實(shí)際上是一個(gè)垂直方向上的 LinearLayout盾致,而且它也是 Design Support 庫(kù)中的空間主经,它在其內(nèi)部做了非常多的滾動(dòng)事件的封裝。先看看如何使用:
<!-- 主布局 -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 在 Toolbar 外層嵌套一個(gè) AppBarLayout -->
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<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">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<!-- 給 ReccylerView 添加一個(gè) app:layout_behavior 屬性庭惜,值也是固定這么寫的 -->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.v7.widget.RecyclerView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:elevation="8dp" />
</android.support.design.widget.CoordinatorLayout>
注意:這里如果將 RecyclerView 也放在 AppBarLayout 中罩驻,則會(huì)無(wú)法滑動(dòng)。如果不給 RecyclerView 添加 app:layout_behavior 屬性护赊,則會(huì)出現(xiàn) RecyclerView 的上面部分被 ToolBar 遮蓋了惠遏,如下圖所示。
??注意頂部骏啰,這個(gè)是 RecyclerView 滑動(dòng)到頂部的樣子节吮,也就是說(shuō) RecyclerView 的上面部分被 ToolBar 遮蓋了。
??當(dāng) AppBarLayout 接收到滾動(dòng)事件的時(shí)候判耕,它內(nèi)部的子控件其實(shí)是可以指定如何去響應(yīng)這些事件的透绩,通過(guò)app:layout_scrollFlags
屬性就可以
<!-- 主布局 -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 在 Toolbar 外層嵌套一個(gè) AppBarLayout -->
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 給 Toolbar 添加了 app:layout_scrollFlags 屬性
其中 scroll 表示當(dāng) RecyclerView 向上滾動(dòng)的時(shí)候,Toolbar 會(huì)跟隨一起向上滾動(dòng)并實(shí)現(xiàn)隱藏;
enterAlways 表示當(dāng)RecyclerView 向下滾動(dòng)的時(shí)候壁熄,Toolbar 會(huì)跟著一起向下滾動(dòng)并重新顯示;
snap 表示當(dāng) Toolbar 還沒有完全隱藏或顯示的時(shí)候帚豪,會(huì)根據(jù)當(dāng)前滾動(dòng)的距離,自動(dòng)選擇是隱藏還是顯示-->
<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"
app:layout_scrollFlags="scroll|enterAlways|snap">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<!-- 給 RecyclerView 添加一個(gè) app:layout_behavior 屬性草丧,值也是固定這么寫的 -->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v7.widget.RecyclerView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:elevation="8dp" />
</android.support.design.widget.CoordinatorLayout>
CardView狸臣、AppBarLayout使用總結(jié):
- 1.CardView 是由 appcompat-v7 庫(kù)提供,實(shí)質(zhì)上是一個(gè) FrameLayout方仿。AppBarLayout是由 Design Support 庫(kù)提供固棚,實(shí)質(zhì)上是一個(gè)垂直方向上的 LinearLayout.
- 2.CardView 中使用 app:cardCornerRadius 屬性指定卡片圓角的弧度,數(shù)值越大仙蚜,圓角的弧度也越大此洲,還可以使用 app:elevation 屬性指定卡片的高度,高度值越大委粉,投影范圍越大呜师,但是投影效果越淡。高度值越小贾节,投影范圍也越小汁汗,但是投影效果越濃。
- 3.解決 RecyclerView 覆蓋 Toolbar 問題栗涂,只需要兩步:第一步 --- 將 Toolbar 嵌套在 AppBarLayout 中知牌;第二步 --- 給RecyclerView 指定一個(gè)布局行為:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
- 4.讓 Toolbar 跟隨 RecyclerView 一起滑動(dòng)的效果:給 Toolbar 設(shè)置屬性
app:layout_scrollFlags="scroll|enterAlways|snap"
其中,scroll 表示 RecyclerView 上滑時(shí)斤程,Toolbar 會(huì)隱藏角寸;enterAlways 表示 RecyclerView 下滑時(shí),Toolbar 會(huì)顯示;snap 表示 Toolbar 沒有完全隱藏或顯示的時(shí)候扁藕,會(huì)根據(jù)當(dāng)前滑動(dòng)的距離沮峡,自動(dòng)選擇隱藏還是顯示。
九亿柑、SwipeRefreshLayout(下拉刷新)
??SwipeRefreshLayout 是由 support-v4 庫(kù)提供邢疙,一般下拉刷新都配合 RecyclerView 一起使用,我們只需要在 RecyclerView 外層嵌套一個(gè) SwipeRefreshLayout 即可望薄。
<!-- 主布局 -->
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 在 Toolbar 外層嵌套一個(gè) AppBarLayout -->
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<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:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:elevation="8dp" />
</android.support.design.widget.CoordinatorLayout>
注意:這里因?yàn)?RecyclerView 外面嵌套了一層 SwipeRefreshLayout 所以疟游,之前設(shè)置的 app:layout_behavior 屬性也必須要放到 SwipeRefreshLayout 中才行。
swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
//設(shè)置下拉刷新進(jìn)度條的顏色痕支,參數(shù)是可變參數(shù)
swipeRefresh.setColorSchemeResources(R.color.colorPrimary,R.color.colorAccent);
//設(shè)置下拉刷新的監(jiān)聽器乡摹,當(dāng)觸發(fā)了下拉刷新操作時(shí),就會(huì)回調(diào)這個(gè)監(jiān)聽器的 onRefresh 方法
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshFruits();
}
});
private void refreshFruits(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initFruits();
adapter.notifyDataSetChanged();
//傳入 false采转,表示刷新事件結(jié)束,并隱藏刷新進(jìn)度條
swipeRefresh.setRefreshing(false);
}
});
}
}).start();
}
十瞬痘、可折疊式標(biāo)題欄
??如果我們希望根據(jù)自己的喜好隨意定制標(biāo)題欄的樣式故慈,比如實(shí)現(xiàn)一個(gè)可折疊式的標(biāo)題欄的效果,就需要借助 CollapsingToolbarLayout 這個(gè)工具框全。
??CollapsingToolbarLayout 是一個(gè)作用于 Toolbar 基礎(chǔ)之上的布局察绷,它也是由 Design Support 庫(kù)提供,CollapsingToolbarLayout 可以讓 Toolbar 的效果變得更加豐富津辩。
注意:CollapsingToolbarLayout 不能獨(dú)立存在拆撼,它在設(shè)計(jì)的時(shí)候就被限定只能作為AppBarLayout 的直接子布局來(lái)使用,而AppBarLayout 又必須是 CoordinatorLayout 的子布局喘沿,所以嵌套的代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="250dp">
<!-- 嵌套在 AppBarLayout 中的 CollapsingToolbarLayout
app:contentScrim 屬性用于指定 CollapsingToolbarLayout 在趨于折疊狀態(tài)
以及折疊之后的背景色闸度,其實(shí) CollapsingToolbarLayout 在折疊后就是一個(gè)普
通的Toolbar。
app:layout_scrollFlags 屬性中 scroll 表示 CollapsingToolbarLayout 會(huì)
隨著內(nèi)容詳情的滾動(dòng)一起滾動(dòng)蚜印,exitUntilCollapsed 表示當(dāng) CollapsingToolbarLayout
會(huì)隨著完成折疊之后就保留在界面上莺禁,不再移出屏幕-->
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<!-- app:layout_collapseMode 屬性指定當(dāng)前控件在 CollapsingToolbarLayout
折疊過(guò)程中的折疊模式,pin 表示在折疊過(guò)程中位置始終保持不變窄赋,parallax 表示
會(huì)在折疊的過(guò)程中產(chǎn)生一定的錯(cuò)位偏移哟冬,視覺效果很好 -->
<ImageView
android:id="@+id/iv_fruit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<!-- NestedScrollView 是在 ScrollView 的基礎(chǔ)之上增加了嵌套
響應(yīng)滾動(dòng)事件的功能,由于 CoordinatorLayout 本身已經(jīng)可以
響應(yīng)滾動(dòng)事件了忆绰,因此我們?cè)趦?nèi)部就需要使用 NestedScrollView
或 RecyclerView 浩峡,而且還加了 app:layout_behavior 屬性,
為了不要遮擋Toolbar -->
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="35dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/tv_fruit_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp" />
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<!-- 使用 app:layout_anchor 屬性指定一個(gè)錨點(diǎn)
使用 app:layout_anchorGravity 屬性將懸浮按鈕定位在標(biāo)題欄區(qū)域的右下角 -->
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"/>
</android.support.design.widget.CoordinatorLayout>
該布局分三部分错敢,最外層是一個(gè) CoordinatorLayout
第一部分:在 CoordinatorLayout 內(nèi)嵌一個(gè) AppBarLayout翰灾,然后在 AppBarLayout 中再內(nèi)嵌一個(gè) CollapsingToolbarLayout劲腿,然后再 CollapsingToolbarLayout 中再加上 ImageView 和 Toolbar 兩個(gè)控件甘凭。
第二部分:加入 NestedScrollView 控件,和 AppBarLayout 是同級(jí)的,在 NestedScrollView 內(nèi)部嵌套一個(gè) LinearLayout触趴,然后在 LinearLayout 中加上 CardView 布局。
第三部分:比較簡(jiǎn)單拼窥,就是加一個(gè)FloatingActionButton抛人,和 AppBarLayout 以及 NestedScrollView 都是同級(jí)的。
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("Apple");
ImageView ivFruit = (ImageView) findViewById(R.id.iv_fruit);
TextView tvFruitContent = (TextView) findViewById(R.id.tv_fruit_content);
Glide.with(this).load(R.mipmap.ic_launcher).into(ivFruit);
tvFruitContent.setText(generateFruitContent("Apple"));
/**
* 生成比較長(zhǎng)的內(nèi)容
*/
private String generateFruitContent(String name) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i++) {
sb.append(name);
}
return sb.toString();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
finish();
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
CollapsingToolbarLayout使用總結(jié):
- 1.CollapsingToolbarLayout 是不能獨(dú)立存在的糜芳,必須作為 AppBarLayout 的直接子布局來(lái)使用飒货,AppBarLayout 又必須是 CoordinatorLayout 的子布局。
- 2.通過(guò)設(shè)置 app:contentScrim 屬性用于指定 CollapsingToolbarLayout 在趨于折疊狀態(tài)和折疊之后的背景色峭竣。還有 app:layout_scrollFlags 屬性塘辅,scroll 表示 CollapsingToolbarLayout 會(huì)隨之一起滾動(dòng),exitUntilCollapsed 表示當(dāng) CollapsingToolbarLayout 隨著滾動(dòng)完成折疊之后就保留在界面上皆撩,不再移出屏幕扣墩。
- 3.CollapsingToolbarLayout 的子控件,可以添加 app:layout_collapseMode 屬性指定當(dāng)前控件在 CollapsingToolbarLayout 折疊過(guò)程中的折疊模式扛吞,pin 表示在折疊的過(guò)程中位置始終保持不變呻惕,parallax 表示會(huì)在折疊的過(guò)程中產(chǎn)生一定的錯(cuò)位偏移。
十一滥比、系統(tǒng)狀態(tài)欄
??在 Android 5.0 系統(tǒng)之前亚脆,我們是無(wú)法對(duì)狀態(tài)欄的背景或顏色進(jìn)行操作的。
??想讓背景圖能夠和系統(tǒng)狀態(tài)欄融合盲泛,需要借助 android:fitsSystemWindows 這個(gè)屬性濒持,在控件中,將該屬性指定為 true寺滚,表示該控件會(huì)出現(xiàn)在系統(tǒng)狀態(tài)欄里柑营,修改布局文件:
這里如果只給 ImageView 設(shè)置 android:fitsSystemWindows 屬性是沒有用的,必須將 ImageView 布局結(jié)構(gòu)中的所有父布局都設(shè)置上這個(gè)屬性才可以村视。
??有點(diǎn)變化由境,但不是我們要的效果。這時(shí)就需要將狀態(tài)欄顏色指定成透明色才行蓖议。
設(shè)置成透明的方法很簡(jiǎn)單虏杰,在主題中將 android:statusBarColor 屬性的值指定成 @android:color/transparent 就可以了,但是問題是勒虾,android:statusBarColor 這個(gè)屬性是從 API 21(Android 5.0)開始才有的纺阔,之前的系統(tǒng)無(wú)法指定這個(gè)屬性。
??為了解決上述問題修然,我們做如下操作
??然后在 values-v21 目錄下創(chuàng)建一個(gè)styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="FruitActivityTheme" parent="AppTheme">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
由于 values-v21 目錄是只有 Android 5.0 及其以上的系統(tǒng)才會(huì)去讀取的笛钝,所以质况,這么寫是沒問題的。但是 Android 5.0 之前的系統(tǒng)卻無(wú)法識(shí)別 FruitActivityTheme 這個(gè)主題玻靡,因此我們還需要修改 values/styles.xml 文件结榄。
<!-- 因?yàn)锳ndroid 5.0 之前的系統(tǒng)無(wú)法指定狀態(tài)欄的顏色,所以這里什么都不用做 -->
<style name="FruitActivityTheme" parent="AppTheme">
</style>
??最后別忘了在清單文件中給 Activity 添加 Theme 屬性
最后囤捻,Material Design 的官方文章:https://material.google.com