Material Design 控件知識(shí)梳理(4) - FloatingActionButton

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:srcFab的圖片坯癣,這其實(shí)是ImageView的屬性瓶盛。
  • app:backgroundTintFab的背景色,如果沒(méi)有設(shè)置示罗,那么會(huì)取theme中的colorAccent作為背景色惩猫。
  • app:fabSizeFab的大小,可選的值包括:
  • mini
  • normal
  • automininormal都預(yù)設(shè)了固定的大小蚜点,而auto屬性則會(huì)根據(jù)屏幕的寬度來(lái)設(shè)置轧房,在小屏幕上使用mini,而在大屏幕上使用normal绍绘,當(dāng)然我們也可以直接通過(guò)layout_width/layout_height來(lái)指定奶镶。
  • app:elevationFabZ軸方向的距離,也就是深度脯倒。
  • app:borderWidthFab邊界的寬度实辑,邊界的顏色會(huì)比背景色稍淡捺氢,如下圖所示

點(diǎn)擊屬性

  • app:pressedTranslationZ:點(diǎn)擊時(shí)FabZ軸的變化值藻丢。
  • app:rippleColor:點(diǎn)擊時(shí)水波紋擴(kuò)散的顏色。

三摄乒、與其它MD控件結(jié)合使用

3.1 和AppBarLayout聯(lián)動(dòng)

通過(guò)給Fab設(shè)置app:layout_anchorlayout_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的方法讓FabBottomSheet聯(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查辩,RecyclerViewFab是它的兩個(gè)子View胖笛,Fab位于CoordinatorLayout的右下角,注意到宜岛,這里我們給Fab設(shè)置了一個(gè)自定義的Behavior长踊,正是通過(guò)這個(gè)behaviorFab可以監(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ò)改變FabtranslationY來(lái)讓它移入或者移出屏幕填硕。

五麦萤、總結(jié)

這篇文章,介紹了Fab的基本用法扁眯、其它MD控件的聯(lián)動(dòng)以及如何自定義FloatingActionButtonBehavior壮莹。


更多文章,歡迎訪問(wèn)我的 Android 知識(shí)梳理系列:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姻檀,一起剝皮案震驚了整個(gè)濱河市命满,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绣版,老刑警劉巖胶台,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異杂抽,居然都是意外死亡诈唬,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)缩麸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)铸磅,“玉大人,你說(shuō)我怎么就攤上這事≡淖校” “怎么了济竹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)霎槐。 經(jīng)常有香客問(wèn)我送浊,道長(zhǎng),這世上最難降的妖魔是什么丘跌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任袭景,我火速辦了婚禮,結(jié)果婚禮上闭树,老公的妹妹穿的比我還像新娘耸棒。我一直安慰自己,他們只是感情好报辱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布与殃。 她就那樣靜靜地躺著,像睡著了一般碍现。 火紅的嫁衣襯著肌膚如雪幅疼。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,792評(píng)論 1 290
  • 那天昼接,我揣著相機(jī)與錄音爽篷,去河邊找鬼。 笑死慢睡,一個(gè)胖子當(dāng)著我的面吹牛逐工,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播漂辐,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼泪喊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了髓涯?” 一聲冷哼從身側(cè)響起袒啼,我...
    開(kāi)封第一講書(shū)人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎复凳,沒(méi)想到半個(gè)月后瘤泪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體灶泵,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡育八,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赦邻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片髓棋。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出按声,到底是詐尸還是另有隱情膳犹,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布签则,位于F島的核電站须床,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏渐裂。R本人自食惡果不足惜豺旬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柒凉。 院中可真熱鬧族阅,春花似錦、人聲如沸膝捞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔬咬。三九已至鲤遥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間林艘,已是汗流浹背渴频。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留北启,地道東北人卜朗。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像咕村,于是被迫代替她去往敵國(guó)和親场钉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容