Material Design系列之Behavior實(shí)現(xiàn)支付密碼彈窗和商品屬性選擇效果
今天的效果在支付寶、淘寶、京東等電商App中很常見。比如支付寶輸入密碼彈窗、商城下單時(shí)選擇商品屬性時(shí),從下面浮動(dòng)上來一個(gè)PopupWindow,那么今天就帶大家用Behavior來實(shí)現(xiàn)這兩個(gè)效果,結(jié)果你會(huì)發(fā)現(xiàn)簡(jiǎn)直只需要一行代碼。
總結(jié)下現(xiàn)在用的APP:
1. 仿支付寶彈出的輸入支付密碼窗口。
2. 仿淘寶/天貓彈出商品屬性選擇框。
3. 知乎首頁上下滑動(dòng)隱藏ToolBar和NavigationBar。
4. …
系列博客:
1. Material Design系列,Behavior之BottomSheetBehavior與BottomSheetDialog
2. Material Design系列,Behavior之SwipeDismissBehavior
3. Material Design系列,自定義Behavior之上滑顯示返回頂部按鈕
4. Material Design系列,自定義Behavior實(shí)現(xiàn)Android知乎首頁
5. Material Design系列,自定義Behavior支持所有 View
效果預(yù)覽
引文
在我的技術(shù)群里有小伙伴們討論Behavior,我也去玩了玩,我也對(duì)Behavior寫了系列博客。選中Behavior然后ctrol + t后發(fā)現(xiàn)Behavior的一個(gè)實(shí)現(xiàn)類:BottomSheetBehavior,我就到Android官網(wǎng)上翻了下資料,一翻就發(fā)現(xiàn)了驚喜啊,下面就把這些驚喜介紹給大家。
更多文章請(qǐng)Google/百度搜索我名字:嚴(yán)振杰,排名第一的就是我。
BottomSheetBehavior怎么玩(知乎Bottom隱藏和顯示)
玩這個(gè)東西,首先Behavior作為CoordinatorLayout的子View的LayoutParams(原因看后文解釋),所以CoordinatorLayout是萬萬不能少的,先來亮出整個(gè)布局:
<android.support.design.widget.CoordinatorLayout 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="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/tab_layout" android:gravity="center" android:orientation="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <Button android:id="@+id/btn_bottom_sheet_control" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="sheet 顯示/隱藏" /> </LinearLayout> <LinearLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="?actionBarSize" android:layout_alignParentBottom="true" android:background="@android:color/holo_purple" app:layout_behavior="@string/bottom_sheet_behavior"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="第一" /> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="第二" /> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="第三" /> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="第四" /> </LinearLayout> </android.support.design.widget.CoordinatorLayout>
大概介紹下,頁面上只能看到Toolbar和一個(gè)Button:sheet 顯示/隱藏,然后android:id="@+id/tab_layout"這個(gè)布局是橫向的,給它設(shè)置了Behavior:app:layout_behavior="@string/bottom_sheet_behavior",經(jīng)過測(cè)試發(fā)現(xiàn),如果不給tab_layout設(shè)置BottomSheetBehavior,它會(huì)浮動(dòng)在整個(gè)頁面的頂部,并在Toolbar的下面。設(shè)置了BottomSheetBehavior它會(huì)被BottomSheetBehavior自動(dòng)移動(dòng)到頁面底部外邊,所以在頁面上是看不到android:id="@+id/tab_layout"這個(gè)布局的。
頁面畫好了,難道它會(huì)自動(dòng)開關(guān)嗎,怎么去控制它的打開和關(guān)閉呢?那么我們就來看看這貨的真實(shí)面貌,經(jīng)過我看Android的官方api發(fā)現(xiàn),BottomSheetBehavior這個(gè)貨有一個(gè)靜態(tài)方法BottomSheetBehavior.from(View),會(huì)返回這個(gè)View引用的BottomSheetBehavior:
public static <V extends View> BottomSheetBehavior<V> from(V view) { ViewGroup.LayoutParams params = view.getLayoutParams(); if (!(params instanceof CoordinatorLayout.LayoutParams)) { throw new Exception("The view is not a child of CoordinatorLayout"); } CoordinatorLayout.Behavior behavior = params.getBehavior(); if (!(behavior instanceof BottomSheetBehavior)) { throw new IllegalArgumentException("..."); } return (BottomSheetBehavior<V>) behavior; }
這個(gè)方法會(huì)檢查這個(gè)View是否是CoordinatorLayout的子View,如果是才會(huì)去拿到這個(gè)View的Behavior,所以諸位也應(yīng)該明白為什么我開頭說Behavior作為CoordinatorLayout子View的LayoutParams了。
接下來我們看看拿到這個(gè)貨后怎么用:
private BottomSheetBehavior mBottomSheetBehavior; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.bsbehavior_activity); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); findViewById(R.id.btn_bottom_sheet_control).setOnClickListener(onClickListener); // 拿到這個(gè)tab_layout對(duì)應(yīng)的BottomSheetBehavior mBottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.tab_layout)); }
findViewById(R.id.btn_bottom_sheet_control).setOnClickListener(onClickListener);是給剛才說的頁面中的Button設(shè)置了監(jiān)聽,我們用這個(gè)按鈕來控制tab_layout的顯示和隱藏。
我發(fā)現(xiàn)有一個(gè)方法可以獲取到它所依附的View此時(shí)的狀態(tài):mBottomSheetBehavior.getState(),翻閱了源碼后發(fā)現(xiàn)它的返回值有以下幾種:
/** * The bottom sheet is dragging. */ public static final int STATE_DRAGGING = 1; /** * The bottom sheet is settling. */ public static final int STATE_SETTLING = 2; /** * The bottom sheet is expanded. */ public static final int STATE_EXPANDED = 3; /** * The bottom sheet is collapsed. */ public static final int STATE_COLLAPSED = 4; /** * The bottom sheet is hidden. */ public static final int STATE_HIDDEN = 5;
當(dāng)我看到STATE_EXPANDED和STATE_COLLAPSED就明白了它的用法了,不就是展開和隱藏起來了麼?所以我們判斷這個(gè)狀態(tài),如果是隱藏就顯示,如果是顯示就隱藏:
@Override public void onClick(View v) { if (v.getId() == R.id.btn_bottom_sheet_control) { if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } else if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) { mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); } } }
到這里,知乎首頁的Bottom的隱藏和顯示也就講玩了,接下來我們來看看支付寶淘寶的下方彈窗如何實(shí)現(xiàn)。
BottomSheetDialog怎么玩(商城下單商品屬性選擇彈窗)
這個(gè)類的發(fā)現(xiàn)也是在Android官網(wǎng)搜索BottomSheetBehavior時(shí)發(fā)現(xiàn)的,一看到BottomSheetDialog后心中狂喜,后來經(jīng)過我驗(yàn)證,它顯示的效果和我猜想的一模一樣啊,既然是個(gè)Dialog,那么用法應(yīng)該和普通Dialog沒啥去區(qū)別了吧。
然后我就順勢(shì)new了一個(gè)BottomSheetDialog:
private BottomSheetDialog mBottomSheetDialog; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... createBottomSheetDialog(); } private void createBottomSheetDialog() { mBottomSheetDialog = new BottomSheetDialog(this); View view = LayoutInflater.from(this).inflate(R.layout.dialog_bottom_sheet, null, false); mBottomSheetDialog.setContentView(view); RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); ... recyclerView.setAdapter(adapter); }
View里面是一個(gè)RecyclerView:
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" />
然后用下面的代碼去控制它的顯示和隱藏。
if (mBottomSheetDialog.isShowing()) { mBottomSheetDialog.dismiss(); } else { mBottomSheetDialog.show(); }
當(dāng)這個(gè)Dialog Show出來的時(shí)候發(fā)現(xiàn)它顯示了一半,嗯這個(gè)效果確實(shí)不錯(cuò),這樣就達(dá)到了我們最初說的支付寶密碼彈窗和淘寶/天貓商品屬性選擇。我們滑動(dòng)的時(shí)候如果下面有內(nèi)容它就會(huì)EXPANDED,如果是一個(gè)普通的View(非RecyclerView、NestedScrollView)將不會(huì)繼續(xù)往上滑動(dòng),下面的內(nèi)容會(huì)繼續(xù)跟著出來,但是同樣可以向下滑動(dòng)隱藏,也可以調(diào)用dismiss和close關(guān)閉。
BottomSheetDialog的神坑
作為一個(gè)有情懷的程序員,這里把我踩過的坑和解決方案跟大家分享一下。
我發(fā)現(xiàn)當(dāng)這個(gè)Dilaog打開再關(guān)閉后,無法用Dialog.show()再次打開,為什么呢?
我去閱讀了一下BottomSheetDialog源代碼,發(fā)現(xiàn)了如下代碼:
@Override public void setContentView(View view, ViewGroup.LayoutParams params) { super.setContentView(wrapInBottomSheet(0, view, params)); } private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) { final CoordinatorLayout coordinator = View.inflate(getContext(),R.layout...., null); FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet); BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback); ... return coordinator; } private BottomSheetCallback mBottomSheetCallback = new BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { dismiss(); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } };
也就是說,系統(tǒng)的BottomSheetDialog是基于BottomSheetBehavior封裝的,這里判斷了當(dāng)我們滑動(dòng)隱藏了BottomSheetBehavior中的View后,內(nèi)部是設(shè)置了BottomSheetBehavior的狀態(tài)為STATE_HIDDEN,接著它替我們關(guān)閉了Dialog,所以我們?cè)俅握{(diào)用dialog.show()的時(shí)候Dialog沒法再此打開狀態(tài)為HIDE的dialog了。
這里就有個(gè)疑問了:
Google為啥沒有提供我們自己設(shè)置BottomSheetCallback的接口呢?
沒有關(guān)系,看了源碼發(fā)現(xiàn)很簡(jiǎn)單,我們自己來實(shí)現(xiàn),并且在監(jiān)聽到用戶滑動(dòng)關(guān)閉BottomSheetDialog后,我們把BottomSheetBehavior的狀態(tài)設(shè)置為BottomSheetBehavior.STATE_COLLAPSED,也就是半個(gè)打開狀態(tài)(BottomSheetBehavior.STATE_EXPANDED為全打開),根據(jù)源碼我把設(shè)置的方法提供下:
private void setBehaviorCallback() { View view = mBottomSheetDialog.getDelegate().findViewById(android.support.design.R.id.design_bottom_sheet); final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(view); bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { mBottomSheetDialog.dismiss(); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); }
這樣就解決了BottomSheetDialog關(guān)閉后不能再次打開的問題了。
源碼下載:http://xiazai.jb51.net/201609/yuanma/AndroidBehavior(jb51.net).rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 學(xué)習(xí)使用Material Design控件(三)使用CardView實(shí)現(xiàn)卡片效果
- 學(xué)習(xí)使用Material Design控件(二)使用DrawerLayout實(shí)現(xiàn)側(cè)滑菜單欄效果
- 學(xué)習(xí)使用Material Design控件(一)
- 微信小程序之MaterialDesign--input組件詳解
- Material Design系列之Behavior實(shí)現(xiàn)Android知乎首頁
- Material Design系列之Behavior上滑顯示返回頂部按鈕
- Material Design系列之自定義Behavior支持所有View
- Android5.0中Material Design的新特性
- Android App仿QQ制作Material Design風(fēng)格沉浸式狀態(tài)欄
- 學(xué)習(xí)使用Material Design控件(四)Android實(shí)現(xiàn)標(biāo)題欄自動(dòng)縮放、放大效果
相關(guān)文章
Android實(shí)現(xiàn)頁面翻轉(zhuǎn)和自動(dòng)翻轉(zhuǎn)功能
這篇文章主要介紹了Android中簡(jiǎn)單實(shí)現(xiàn)頁面翻轉(zhuǎn)和自動(dòng)翻轉(zhuǎn)的功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10Android中實(shí)現(xiàn)可滑動(dòng)的Tab的3種方式
這篇文章主要介紹了Android中實(shí)現(xiàn)可滑動(dòng)的Tab的3種方式,需要的朋友可以參考下2014-02-02Android編程自定義菜單實(shí)現(xiàn)方法詳解
這篇文章主要介紹了Android編程自定義菜單實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Android自定義菜單的布局、動(dòng)畫及功能相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2017-02-02Android賬號(hào)注冊(cè)實(shí)現(xiàn)點(diǎn)擊獲取驗(yàn)證碼倒計(jì)時(shí)效果
這篇文章主要為大家詳細(xì)介紹了Android賬號(hào)注冊(cè)過程中實(shí)現(xiàn)點(diǎn)擊獲取驗(yàn)證碼倒計(jì)時(shí)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05android模擬器開發(fā)和測(cè)試nfc應(yīng)用實(shí)例詳解
本文介紹android模擬器開發(fā)nfc應(yīng)用詳解,大家參考使用吧2013-12-12Android studio開發(fā)小型對(duì)話機(jī)器人app(實(shí)例代碼)
這篇文章主要介紹了Android studio開發(fā)一個(gè)小型對(duì)話機(jī)器人app,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android使用SoundPool實(shí)現(xiàn)播放音效
這篇文章主要為大家詳細(xì)介紹了Android使用SoundPool實(shí)現(xiàn)播放音效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11Android 個(gè)人理財(cái)工具一:項(xiàng)目概述與啟動(dòng)界面的實(shí)現(xiàn)
本文主要介紹Android 開發(fā)個(gè)人理財(cái)工具項(xiàng)目概述與啟動(dòng)界面的實(shí)現(xiàn),這里主要對(duì)實(shí)現(xiàn)項(xiàng)目的流程做了詳細(xì)概述,并對(duì)啟動(dòng)界面簡(jiǎn)單實(shí)現(xiàn),有需要的小伙伴可以參考下2016-08-08