Material Design系列之BottomSheet詳解

Material Design系列之BottomSheet詳解

BottomSheetBehavior官方文檔

BottomSheetDialog官方文檔

BottomSheetDialogFragment官方文檔

Material Design官方文檔Sheets: bottom的介紹

簡(jiǎn)介

BottomSheet可以理解為底部對(duì)話框音念,類似popwindow實(shí)現(xiàn)的效果

BottomSheet有兩種類型:

一躬翁、沒(méi)有蒙層姊途,可以對(duì)沒(méi)有遮蓋住的地方進(jìn)行操作贺辰,類似百度地圖查詢路線的頁(yè)面;


圖片1

二、有蒙層效果,就是和正常的popwindow使用效果一樣了廊镜。


圖片2
使用

compile 'com.android.support:design:26.0.0-alpha1'

1、BottomSheetBehavior的使用

依賴于CoordinatorLayout和BottomSheetBehavior唉俗,需要將底部菜單布局作為CoordinatorLayout的子View嗤朴,實(shí)現(xiàn)簡(jiǎn)單但不夠靈活,適用于底部菜單布局穩(wěn)定的情況虫溜。

<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:orientation="vertical"
    tools:context="com.wangshuai.androidui.material.BottomSheetActivity">

    <include layout="@layout/content_main" />

    <include layout="@layout/content_bottom_sheet" />


</android.support.design.widget.CoordinatorLayout>

content_bottom_sheet布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:id="@+id/ll_content_bottom_sheet"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              app:behavior_hideable="true"
              app:behavior_peekHeight="50dp"
              app:layout_behavior="@string/bottom_sheet_behavior"
    android:background="@color/white">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:text="人生若只如初見(jiàn)雹姊,何事秋風(fēng)悲畫(huà)扇。"
        android:textSize="20sp"
        android:gravity="center"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:text="等閑變卻故人心衡楞,卻道故人心易變容为。"
        android:textSize="20sp"
        android:gravity="center"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:text="驪山語(yǔ)罷清宵半,淚雨霖鈴終不怨。"
        android:textSize="20sp"
        android:gravity="center"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:text="何如薄幸錦衣郎坎背,比翼連枝當(dāng)日愿。"
        android:textSize="20sp"
        android:gravity="center"/>

</LinearLayout>

其中app:behavior_hideable="true"表示可以讓bottom sheet完全隱藏寄雀,默認(rèn)為false得滤;

app:behavior_peekHeight="60dp"表示當(dāng)為STATE_COLLAPSED(折疊)狀態(tài)的時(shí)候bottom sheet殘留的高度,默認(rèn)為0盒犹。

app:layout_behavior="@string/bottom_sheet_behavior"這個(gè)一定要設(shè)置懂更,不然起不到效果。

通過(guò)BottomSheetBehavior控制content_bottom_sheet布局的顯示和隱藏

bottomSheetBehavior = BottomSheetBehavior.from(llContentBottomSheet);
        bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {

                switch (newState) {
                    case BottomSheetBehavior.STATE_COLLAPSED:
                        Log.e("Bottom Sheet Behaviour", "STATE_COLLAPSED");
                        break;
                    case BottomSheetBehavior.STATE_DRAGGING:
                        Log.e("Bottom Sheet Behaviour", "STATE_DRAGGING");
                        break;
                    case BottomSheetBehavior.STATE_EXPANDED:
                        Log.e("Bottom Sheet Behaviour", "STATE_EXPANDED");
                        break;
                    case BottomSheetBehavior.STATE_HIDDEN:
                        Log.e("Bottom Sheet Behaviour", "STATE_HIDDEN");
                        break;
                    case BottomSheetBehavior.STATE_SETTLING:
                        Log.e("Bottom Sheet Behaviour", "STATE_SETTLING");
                        break;
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

            }
        });

            case R.id.btn_expand://展開(kāi)
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                break;
            case R.id.btn_collapsed://折疊
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                break;
            case R.id.btn_hide://隱藏
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
                break;

Bottom Sheet有五種狀態(tài):

  • STATE_COLLAPSED:折疊狀態(tài)急膀,bottom sheets只在底部顯示一部分布局沮协。顯示高度可以通過(guò) app:behavior_peekHeight 設(shè)置;
  • STATE_DRAGGING:過(guò)渡狀態(tài)卓嫂,此時(shí)用戶正在向上或者向下拖動(dòng)bottom sheet慷暂;
  • STATE_SETTLING: 視圖從脫離手指自由滑動(dòng)到最終停下的這一小段時(shí)間
  • STATE_EXPANDED: 完全展開(kāi)的狀態(tài)
  • STATE_HIDDEN: 隱藏狀態(tài)。默認(rèn)是false晨雳,可通過(guò)app:behavior_hideable屬性設(shè)置是否能隱藏

這種使用方法是沒(méi)有蒙層行瑞,可以對(duì)其他控件進(jìn)行操作。

2餐禁、BottomSheetDialog的使用

BottomSheetDialog的使用就和對(duì)話框差不多血久。會(huì)出現(xiàn)蒙層,只能對(duì)彈出的頁(yè)面進(jìn)行操作帮非。

                if (dialog == null){
                    dialog = new BottomSheetDialog(this);
                }
                dialog.setCancelable(false);
                dialog.setCanceledOnTouchOutside(true);
                View view =LayoutInflater.from(BottomSheetActivity.this).inflate(R.layout.content_bottom_sheet_dialog,null);
                TextView tvWechat = view.findViewById(R.id.tv_wechat);
                tvWechat.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(BottomSheetActivity.this,"微信",Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }
                });
                dialog.setContentView(view);
                dialog.show();

BottomSheetDialog部分源碼:

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
        final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(),
                R.layout.design_bottom_sheet_dialog, null);
        if (layoutResId != 0 && view == null) {
            view = getLayoutInflater().inflate(layoutResId, coordinator, false);
        }
        FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
        mBehavior = BottomSheetBehavior.from(bottomSheet);
        mBehavior.setBottomSheetCallback(mBottomSheetCallback);
        mBehavior.setHideable(mCancelable);
        if (params == null) {
            bottomSheet.addView(view);
        } else {
            bottomSheet.addView(view, params);
        }
        // We treat the CoordinatorLayout as outside the dialog though it is technically inside
        coordinator.findViewById(R.id.touch_outside).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mCancelable && isShowing() && shouldWindowCloseOnTouchOutside()) {
                    cancel();
                }
            }
        });
        // Handle accessibility events
        ViewCompat.setAccessibilityDelegate(bottomSheet, new AccessibilityDelegateCompat() {
            @Override
            public void onInitializeAccessibilityNodeInfo(View host,
                    AccessibilityNodeInfoCompat info) {
                super.onInitializeAccessibilityNodeInfo(host, info);
                if (mCancelable) {
                    info.addAction(AccessibilityNodeInfoCompat.ACTION_DISMISS);
                    info.setDismissable(true);
                } else {
                    info.setDismissable(false);
                }
            }

            @Override
            public boolean performAccessibilityAction(View host, int action, Bundle args) {
                if (action == AccessibilityNodeInfoCompat.ACTION_DISMISS && mCancelable) {
                    cancel();
                    return true;
                }
                return super.performAccessibilityAction(host, action, args);
            }
        });
        bottomSheet.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                // Consume the event and prevent it from falling through
                return true;
            }
        });
        return coordinator;
    }

由源碼可知氧吐,BottomSheetDialog的setContentView最終是被CoordinatorLayout包裹住。

3末盔、BottomSheetDialogFragment的使用

BottomSheetDialogFragment的使用和fragment一樣筑舅。可以幫助我們實(shí)現(xiàn)全屏的BottomSheet展示效果

CustomFragmentDialog fragmentDialog = new CustomFragmentDialog();
fragmentDialog.show(getSupportFragmentManager(),"CustomFragmentDialog");

public class CustomFragmentDialog extends BottomSheetDialogFragment {
    private ArrayList<String> list = new ArrayList<>();

    public CustomFragmentDialog() {
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.content_bottom_sheet_fragment_dialog,container, false);
        initViews(view);
        return view;
    }

    private void initViews(View view) {
        for (int i = 0;i < 100;i++){
            list.add("條目"+i);
        }
        RecyclerView recyclerView = view.findViewById(R.id.rv_item);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        RecyclerViewAdapter adapter = new RecyclerViewAdapter(list);
        recyclerView.setAdapter(adapter);
    }

}

/**
 * 全屏顯示
 */
public class FullSheetDialogFragment extends BottomSheetDialogFragment{

    private BottomSheetBehavior mBehavior;
    private ArrayList<String> list = new ArrayList<>();

    public FullSheetDialogFragment() {
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
        View view = View.inflate(getContext(), R.layout.content_bottom_sheet_fragment_dialog, null);
        initViews(view);
        dialog.setContentView(view);
        mBehavior = BottomSheetBehavior.from((View) view.getParent());

        return dialog;
    }

    private void initViews(View view) {
        for (int i = 0;i < 100;i++){
            list.add("條目"+i);
        }
        RecyclerView recyclerView = view.findViewById(R.id.rv_item);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        RecyclerViewAdapter adapter = new RecyclerViewAdapter(list);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void onStart()
    {
        super.onStart();
        mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);//全屏展開(kāi)
    }

}
使用bottom sheet的問(wèn)題

BottomSheetDialog沉浸式的一些坑

解決使用BottomSheetDialog時(shí)狀態(tài)欄變黑的問(wèn)題

Github示例代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末庄岖,一起剝皮案震驚了整個(gè)濱河市豁翎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隅忿,老刑警劉巖心剥,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異背桐,居然都是意外死亡优烧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門链峭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)畦娄,“玉大人,你說(shuō)我怎么就攤上這事∥蹩ǎ” “怎么了杖刷?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)驳癌。 經(jīng)常有香客問(wèn)我滑燃,道長(zhǎng),這世上最難降的妖魔是什么颓鲜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任表窘,我火速辦了婚禮,結(jié)果婚禮上甜滨,老公的妹妹穿的比我還像新娘乐严。我一直安慰自己,他們只是感情好衣摩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布昂验。 她就那樣靜靜地躺著,像睡著了一般昭娩。 火紅的嫁衣襯著肌膚如雪凛篙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天栏渺,我揣著相機(jī)與錄音呛梆,去河邊找鬼。 笑死磕诊,一個(gè)胖子當(dāng)著我的面吹牛填物,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霎终,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼滞磺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了莱褒?” 一聲冷哼從身側(cè)響起击困,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎广凸,沒(méi)想到半個(gè)月后阅茶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谅海,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年脸哀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扭吁。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撞蜂,死狀恐怖盲镶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝌诡,我是刑警寧澤溉贿,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站送漠,受9級(jí)特大地震影響顽照,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜闽寡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尼酿。 院中可真熱鬧爷狈,春花似錦、人聲如沸裳擎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鹿响。三九已至羡微,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惶我,已是汗流浹背妈倔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绸贡,地道東北人盯蝴。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像听怕,于是被迫代替她去往敵國(guó)和親捧挺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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