Material Design
我的更多 Android 博文,關(guān)注作者~每周更新一篇 Android干貨博文
http://xuyushi./archives/
吐槽
作為一個(gè) Android developer,沒有什么比拿著 UI 設(shè)計(jì)的一堆 iOS 風(fēng)格的設(shè)計(jì) 來做需求更惡心的了,基本所有空間都要照著 iOS 來畫一遍,Material Design 辣么酷炫 為什么 UI在設(shè)計(jì)的階段不設(shè)計(jì)成 Material Design風(fēng)格呢?
今天試了幾個(gè)比較Support包中比較典型的Material Design控件,后期會(huì)在學(xué)習(xí)下Material Design的設(shè)計(jì)思想和理念,希望能拉著 UI 做一次Material Design 分享,改變我們 APP 的 iOS 風(fēng)格啊。
最終效果如下
Android Design Support 庫依賴
在 build.gradle 中加入support 包
compile 'com.android.support:appcompat-v7:23.1.1'
Design Support Library 中包含了 Support v4 和 AppCompat v7
Floating Action Button
我們希望FloatingActionButton 懸浮在頁面的右下方,所以我們父節(jié)點(diǎn)應(yīng)使用Flowlayout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas./apk/res/android"
xmlns:tools="http://schemas./tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="io.github.xuyushi.materialdesigndemo.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:src="@android:drawable/ic_dialog_email" />
</FrameLayout>
和普通 button 一樣可以設(shè)置其點(diǎn)擊事件
private void initFb() {
mFb = (FloatingActionButton) findViewById(R.id.fb);
mFb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "fb predsed ", Toast.LENGTH_SHORT).show();
}
});
}
Android:elevation 屬性為 view 在空閑狀態(tài)下的陰影深度, 需要在 api 21以上才能使用,使用
support 包可以使用app:elevation 來表示空閑狀態(tài)高度,app:pressedTanslationZ 為按下狀態(tài)的高度
按鈕的顏色一般為主題的強(qiáng)調(diào)色,也可以使用 ”app:backgroundTint“修改
Snackbar
和 Toast 很像,snackbar 可以展示一段簡單的信息,不同點(diǎn)是它的展示更像是整體 UI 的一部分,不是想 toast 一樣是浮在 UI 上的,并且可以有簡單的交互
在點(diǎn)擊 floatingActionButton時(shí)顯示Snackbar
但是可以看到,Snackbar 遮擋住了我們的 view,這時(shí)候需要一個(gè)CoordinatorLayout 來協(xié)調(diào)
view 布局
CoordinatorLayout
將父布局中的framelaout 換成CoordinatorLayout ,其他不變,再來看看效果
==todo CoordinatorLayout學(xué)習(xí)==
Toolbar
Toolbar 比傳統(tǒng)的 ActionBar 更靈活,功能也更多,我們可以看到現(xiàn)在市面上很多的 APP 已經(jīng)用 Toolbar 替代了 actionbar,在 Desgin Support 的組件中,很多設(shè)計(jì)都可以和 Toolbar 協(xié)同工作,而不是和 actionbar,所以還是建議使用新的 toolbar 替換以前的 actionbar
替換步驟
1、在 minifest 中,將 activity 的 apptheme 的 style 中的 actionbar屬性去掉
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- 在 fb 之前放入 Toolbar 組件
<android.support.design.widget.CoordinatorLayout
.........
<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" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="@android:drawable/ic_dialog_email"
app:elevation="12dp"
app:pressedTranslationZ="30dp"
/>
</android.support.design.widget.CoordinatorLayout>
- 通知系統(tǒng)使用 toolbar
private void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
}
CoordinatorLayout 中的 view 必須是能一同協(xié)作的 view,就像 Snackbar
一樣,但是 toolbar 并不是這樣能協(xié)同作戰(zhàn)的 view,所以我們需要用一個(gè)可以協(xié)同作戰(zhàn)的 view 來包裹上Toolbar ,這就是 AppBarLayout
現(xiàn)在我們的布局文件結(jié)構(gòu)是這樣的
<android.support.design.widget.CoordinatorLayout
...>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.FloatingActionButton
...>
</android.support.design.widget.FloatingActionButton>
</android.support.design.widget.CoordinatorLayout>
注意
根據(jù)官方的谷歌文檔,AppBarLayout目前必須是第一個(gè)嵌套在CoordinatorLayout里面的子view
在 toolbar 中加入屬性,app:layout_collapseMode="pin",使得 Toolbar 中的按鈕能固定在頂部
在布局中加入內(nèi)容
在布局中嘗試加入一些按鈕
....
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test" />
</LinearLayout>
...
我們定義三個(gè)按鍵,卻被 toolbar 遮住了一個(gè),原因是LinearLayout 并沒有被設(shè)計(jì)成在CoordinatorLayout 協(xié)同工作的模式,為了使他們能在CoordinatorLayout 協(xié)同工作,我們需要在LinearLayout 加上一條屬性,來告訴它的滾動(dòng)屬性()
<LinearLayout
...
app:layout_behavior="@string/appbar_scrolling_view_behavior"
...
>
搞定
TabLayout
根據(jù)官網(wǎng)的知道,TabLayout 通常應(yīng)該是放在頂部,(iOS 的 tab 好像基本在底部),
他應(yīng)該在陰影部分上面,所以應(yīng)該放在AppBarlayout 中
<android.support.design.widget.AppBarLayout ...>
<android.support.v7.widget.Toolbar ... />
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
Java 中設(shè)置這些 tab 屬性
private void initTableLayout() {
mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
mTabLayout.addTab(mTabLayout.newTab().setText("Tab 1"));
mTabLayout.addTab(mTabLayout.newTab().setText("Tab 2"));
mTabLayout.addTab(mTabLayout.newTab().setText("Tab 3"));
}
背景會(huì)設(shè)置為主題色,導(dǎo)航線是強(qiáng)調(diào)色。但是字還是黑色的,因?yàn)槲覀儧]有為 tablayout 定義主題,
<android.support.design.widget.TabLayout
...
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
通常 tablayout 會(huì)和ViewPager 一起使用 ,這時(shí)候使用
public void setupWithViewPager (ViewPager viewPager)
一張圖看的比較清晰
內(nèi)容滾動(dòng)時(shí),AppBarLayout隱藏
當(dāng)滑檔內(nèi)容時(shí),為了騰出跟多的空間展示內(nèi)容可以將AppBarLayout 隱藏
1.用 scrollView 包裹 LinearLayout,記得加上 app:layout_behavior 屬性
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
...
</LinearLayout>
</ScrollView>
- Toolbar 加上屬性
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways" />
- scrollView 也不能喝 CoordinatorLayout 協(xié)同工作,同上面一樣,要用別的 view 包裹或者直接使用 NestedSrollView替換scrollView
如果希望 tablayout 也消失,只需要和 tablayout 加上相同的屬性就行了
<android.support.design.widget.TabLayout
...
app:layout_scrollFlags="scroll|enterAlways" />
滑動(dòng)內(nèi)容 和 AppBarLayout是如何進(jìn)行聯(lián)系的?
我們需要定義AppBarLayout與滾動(dòng)視圖之間的聯(lián)系。在RecyclerView或者任意支持嵌套滾動(dòng)的view比如NestedScrollView上添加app:layout_behavior。support library包含了一個(gè)特殊的字符串資源@string/appbar_scrolling_view_behavior,它和AppBarLayout.ScrollingViewBehavior相匹配,用來通知AppBarLayout 這個(gè)特殊的view何時(shí)發(fā)生了滾動(dòng)事件,這個(gè)behavior需要設(shè)置在觸發(fā)事件(滾動(dòng))的view之上
當(dāng)CoordinatorLayout發(fā)現(xiàn)scrollView中定義了這個(gè)屬性,它會(huì)搜索自己所包含的其他view,看看是否有view與這個(gè)behavior相關(guān)聯(lián)。AppBarLayout.ScrollingViewBehavior描述了RecyclerView與AppBarLayout之間的依賴關(guān)系。RecyclerView的任意滾動(dòng)事件都將觸發(fā)AppBarLayout或者AppBarLayout里面view的改變。
AppBarLayout里面定義的view只要設(shè)置了app:layout_scrollFlags屬性,就可以在RecyclerView滾動(dòng)事件發(fā)生的時(shí)候被觸發(fā):
app:layout_scrollFlags屬性里面必須至少啟用scroll這個(gè)flag,這樣這個(gè)view才會(huì)滾動(dòng)出屏幕,否則它將一直固定在頂部。可以使用的其他flag有:
- enterAlways: 一旦向上滾動(dòng)這個(gè)view就可見。
- enterAlwaysCollapsed: 顧名思義,這個(gè)flag定義的是何時(shí)進(jìn)入(已經(jīng)消失之后何時(shí)再次顯示)。假設(shè)你定義了一個(gè)最小高度(minHeight)同時(shí)enterAlways也定義了,那么view將在到達(dá)這個(gè)最小高度的時(shí)候開始顯示,并且從這個(gè)時(shí)候開始慢慢展開,當(dāng)滾動(dòng)到頂部的時(shí)候展開完。
- exitUntilCollapsed: 同樣顧名思義,這個(gè)flag時(shí)定義何時(shí)退出,當(dāng)你定義了一個(gè)minHeight,這個(gè)view將在滾動(dòng)到達(dá)這個(gè)最小高度的時(shí)候消失。
記住,要把帶有scroll flag的view放在前面,這樣收回的view才能讓正常退出,而固定的view繼續(xù)留在頂部。
可折疊的 Toolbar
- 用 CollapsingToolbarLayout 包裹 Toolbar,但仍然在 AppBarLayout 中
- 刪除 Toolbar 中的 layout_scrollFlags
- 為 CollapsingToolbarLayout 聲明 layout_scrollFlags,并且將 layout_scrollFlags 設(shè)置成 scroll|exitUntilCollapsed
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="256dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
注意 CollapsingToolbarLayout 的高度是android:layout_height="match_parent"
CollapsingToolbarLayout在展開和收縮時(shí),標(biāo)題的文字會(huì)自動(dòng)過度的,可以通過 app:expandedTitleMargin 等來改變文字位置
為 appBar 添加背景圖片
由于 CollapsingToolbarLayout 是繼承 Framelayout 的,所以我們可以直接添加一個(gè) ImageView 作為背景圖片
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/header" />
<android.support.v7.widget.Toolbar
...
此時(shí)雖然背景已經(jīng)出來了,但是藍(lán)色的導(dǎo)航條依舊存在,需要在 toolbar 去掉這條屬性
android:background="?attr/colorPrimary"
給 Imageview 加上視差模式會(huì)更帥
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5"
也可以在最后恢復(fù)成主題色
<android.support.design.widget.CollapsingToolbarLayout
...
app:contentScrim="?attr/colorPrimary">
Navigation Drawer
在AppBarLayout 布局下,增DrawerLayout
<android.support.design.widget.AppBarLayout>
...
<android.support.v4.widget.DrawerLayout xmlns:app="http://schemas./apk/res-auto"
xmlns:tools="http://schemas./tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:openDrawer="start">
<include layout="@layout/content_main" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main2"
app:menu="@menu/activity_main2_drawer" />
</android.support.v4.widget.DrawerLayout>
DrawerLayout 中分兩部分組成,一部分是content 就是我們需要的主布局內(nèi)容,另一部分是我們的抽屜的布局,NavigationView中有頂部頭,和標(biāo)簽
app:headerLayout="@layout/nav_header_main2"
app:menu="@menu/activity_main2_drawer"
創(chuàng)建菜單。
菜單元素是放在group標(biāo)簽之下,同時(shí)聲明每次只能有一個(gè)item被選中:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas./apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_camera"
android:icon="@drawable/ic_menu_camera"
android:title="Import" />
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="Gallery" />
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_menu_slideshow"
android:title="Slideshow" />
<item
android:id="@+id/nav_manage"
android:icon="@drawable/ic_menu_manage"
android:title="Tools" />
</group>
<item android:title="Communicate">
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_menu_share"
android:title="Share" />
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_menu_send"
android:title="Send" />
</menu>
</item>
</menu>
為了防止頁面被遮蓋,同樣要使得 DrawerLayout 協(xié)調(diào)。加入app:layout_behavior="@string/appbar_scrolling_view_behavior" 屬性
java初始化
private void initDraw() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
});
SwipeRefreshLayout
在NestedScrollView 外在包裹一層SwipeRefreshLayout ,
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
>
.....
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
初始化監(jiān)聽器
private void initRefresh() {
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshContent();
}
});
}
private void refreshContent() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
}
}, 2000);
}
我的更多 android 博文,關(guān)注作者~每周更新一篇 Android干貨博文
http://xuyushi./archives/
參考
http:///blog/android-design-support-library-codelab/en
http://www./a/anzhuokaifa/androidkaifa/2015/0717/3196.html
http://www./a/anzhuokaifa/androidkaifa/2015/0608/3011.html
http://developer./design/material/
|