Material Design 控件知識(shí)梳理(1) - Android Design Support Library 是什么
Material Design 控件知識(shí)梳理(2) - AppBarLayout & CollapsingToolbarLayout
Material Design 控件知識(shí)梳理(3) - BottomSheet && BottomSheetDialog && BottomSheetDialogFragment
Material Design 控件知識(shí)梳理(4) - FloatingActionButton
Material Design 控件知識(shí)梳理(5) - DrawerLayout && NavigationView
Material Design 控件知識(shí)梳理(6) - Snackbar
Material Design 控件知識(shí)梳理(7) - BottomNavigationBar
Material Design 控件知識(shí)梳理(8) - TabLayout
Material Design 控件知識(shí)梳理(9) - TextInputLayout
一、概述
今天,我們介紹一個(gè)比較簡(jiǎn)單的控件:FloatingActionButton
惶傻,相信大家一定都聽(tīng)過(guò)也在網(wǎng)上見(jiàn)過(guò)類(lèi)似的例子安券,我們就分為三個(gè)部分介紹一下FloatingActionButton
的相關(guān)知識(shí):
-
Fab
的基礎(chǔ)使用 -
Fab
和其它MD
控件的組合 - 通過(guò)自定義
FloatingActionButton.Behavior
氢惋,讓Fab
根據(jù)列表的狀態(tài)顯示和隱藏
二区匣、Fab
的基礎(chǔ)使用
Fab
本質(zhì)上其實(shí)是一個(gè)ImageButton
,只是它在ImageButton
的基礎(chǔ)上增加了一些屬性养匈,這里介紹幾個(gè)常用的屬性:
展現(xiàn)屬性
-
android:src
:Fab
的圖片坯癣,這其實(shí)是ImageView
的屬性瓶盛。 -
app:backgroundTint
:Fab
的背景色,如果沒(méi)有設(shè)置示罗,那么會(huì)取theme
中的colorAccent
作為背景色惩猫。 -
app:fabSize
:Fab
的大小,可選的值包括: -
mini
: normal
-
auto
:mini
和normal
都預(yù)設(shè)了固定的大小蚜点,而auto
屬性則會(huì)根據(jù)屏幕的寬度來(lái)設(shè)置轧房,在小屏幕上使用mini
,而在大屏幕上使用normal
绍绘,當(dāng)然我們也可以直接通過(guò)layout_width/layout_height
來(lái)指定奶镶。 -
app:elevation
:Fab
在Z
軸方向的距離,也就是深度脯倒。 -
app:borderWidth
:Fab
邊界的寬度实辑,邊界的顏色會(huì)比背景色稍淡捺氢,如下圖所示
點(diǎn)擊屬性
-
app:pressedTranslationZ
:點(diǎn)擊時(shí)Fab
在Z
軸的變化值藻丢。 -
app:rippleColor
:點(diǎn)擊時(shí)水波紋擴(kuò)散的顏色。
三摄乒、與其它MD
控件結(jié)合使用
3.1 和AppBarLayout
聯(lián)動(dòng)
通過(guò)給Fab
設(shè)置app:layout_anchor
和layout_anchorGravity
兩個(gè)屬性悠反,可以讓Fab
跟隨AppBarLayout
移動(dòng),并在合適的時(shí)候隱藏馍佑,下面是我們的布局:
<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"
tools:context="com.demo.lizejun.repotransition.FABActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/al_title"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_title"
android:src="@drawable/ic_bg"
android:layout_width="match_parent"
android:scaleType="centerCrop"
android:layout_height="150dp"
app:layout_scrollFlags="scroll"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_btn_speak_now"
android:layout_margin="10dp"
app:backgroundTint="@color/colorPrimary"
app:layout_anchor="@id/al_title"
app:layout_anchorGravity="bottom|end"/>
</android.support.design.widget.CoordinatorLayout>
當(dāng)我們滾動(dòng)布局的時(shí)候斋否,Fab
會(huì)跟著AppBarLayout
先上移,然后消失:
3.2 和BottomSheet
聯(lián)動(dòng)
和AppBarLayout
類(lèi)似拭荤,我們也可以通過(guò)設(shè)置layout_anchor
的方法讓Fab
和BottomSheet
聯(lián)動(dòng):
<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"
tools:context="com.demo.lizejun.repotransition.FABActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/al_title"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_title"
android:src="@drawable/ic_bg"
android:layout_width="match_parent"
android:scaleType="centerCrop"
android:layout_height="150dp"
app:layout_scrollFlags="scroll"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<include android:id="@+id/bottom_sheet" layout="@layout/layout_bottom_sheet_linear"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_btn_speak_now"
android:layout_margin="10dp"
app:backgroundTint="@color/colorPrimary"
app:layout_anchor="@id/bottom_sheet"
app:layout_anchorGravity="end"/>
</android.support.design.widget.CoordinatorLayout>
這里茵臭,我們把layout_anchor
設(shè)為bottom_sheet
:
3.3 和Snackbar
聯(lián)動(dòng)
需要和Snackbar
聯(lián)動(dòng)時(shí),不需要Fab
設(shè)置layout_anchor
舅世,而是需要在Snackbar
展現(xiàn)的時(shí)候旦委,第一個(gè)參數(shù)傳入的是CoordinatorLayout
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fab);
initView();
mRootView = (CoordinatorLayout) findViewById(R.id.cl_root);
mFab = (FloatingActionButton) findViewById(R.id.fab);
mFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//這里需要傳入CoordinatorLayout
Snackbar.make(mRootView, "點(diǎn)擊Fab", Snackbar.LENGTH_LONG).show();
}
});
}
下面是展現(xiàn)的效果:
四奇徒、Fab
根據(jù)列表的狀態(tài)顯示或隱藏
在Fab
的內(nèi)部,定義了一個(gè)Behavior
缨硝,我們可以通過(guò)繼承這個(gè)Behavior
來(lái)監(jiān)聽(tīng)CoordinatorLayout
內(nèi)布局的變化摩钙,以實(shí)現(xiàn)Fab
的顯示和隱藏,首先看我們的布局:
<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:id="@+id/cl_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.demo.lizejun.repotransition.FABActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_content"
android:tag="rv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_btn_speak_now"
android:layout_margin="10dp"
android:layout_gravity="bottom|end"
app:backgroundTint="@color/colorPrimary"
app:layout_behavior="com.demo.lizejun.repotransition.behavior.FabListBehavior"/>
</android.support.design.widget.CoordinatorLayout>
我們的根布局是一個(gè)CoordinatorLayout
查辩,RecyclerView
和Fab
是它的兩個(gè)子View
胖笛,Fab
位于CoordinatorLayout
的右下角,注意到宜岛,這里我們給Fab
設(shè)置了一個(gè)自定義的Behavior
长踊,正是通過(guò)這個(gè)behavior
,Fab
可以監(jiān)聽(tīng)到CoordinatorLayout
內(nèi)布局的滾動(dòng)情況谬返,下面是我們的Behavior
:
public class FabListBehavior extends FloatingActionButton.Behavior {
private static final int MIN_CHANGED_DISTANCE = 30;
public FabListBehavior(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
return true;
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
if (dyConsumed > MIN_CHANGED_DISTANCE) {
createValueAnimator(coordinatorLayout, child, false).start();
} else if (dyConsumed < -MIN_CHANGED_DISTANCE) {
createValueAnimator(coordinatorLayout, child, true).start();
}
}
private Animator createValueAnimator(CoordinatorLayout coordinatorLayout, final View fab, boolean dismiss) {
int distanceToDismiss = coordinatorLayout.getBottom() - fab.getBottom() + fab.getHeight();
int end = dismiss ? 0 : distanceToDismiss;
float start = fab.getTranslationY();
ValueAnimator animator = ValueAnimator.ofFloat(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
fab.setTranslationY((Float) animation.getAnimatedValue());
}
});
return animator;
}
}
這里之斯,我們繼承于FloatingActionButton.Behavior
來(lái)實(shí)現(xiàn)自己的Behavior
,注意遣铝,必須要聲明構(gòu)造函數(shù)為FabListBehavior(Context, AttributeSet)
佑刷,并調(diào)用super()
方法,否則會(huì)無(wú)法實(shí)例化:
-
onStartNestedScroll
決定了之后是否需要回調(diào)onNestedScroll
酿炸,這里我們直接返回true
瘫絮。 -
onNestedScroll
:我們根據(jù)dyConsumed
的正負(fù)值來(lái)判斷列表滾動(dòng)的方法,然后通過(guò)改變Fab
的translationY
來(lái)讓它移入或者移出屏幕填硕。
五麦萤、總結(jié)
這篇文章,介紹了Fab
的基本用法扁眯、其它MD
控件的聯(lián)動(dòng)以及如何自定義FloatingActionButtonBehavior
壮莹。
更多文章,歡迎訪問(wèn)我的 Android 知識(shí)梳理系列:
- Android 知識(shí)梳理目錄:http://www.reibang.com/p/fd82d18994ce
- 個(gè)人主頁(yè):http://lizejun.cn
- 個(gè)人知識(shí)總結(jié)目錄:http://lizejun.cn/categories/