android BottomSheetDialog新控件解析實(shí)現(xiàn)知乎評(píng)論列表效果(實(shí)例代碼)
BottomSheetDialog使用解析
Android Support Library 23.2里的 Design Support Library新加了一個(gè)Bottom Sheets控件,Bottom Sheets顧名思義就是底部操作控件,用于在屏幕底部創(chuàng)建一個(gè)可滑動(dòng)關(guān)閉的視圖,可以替代對(duì)話框和菜單。其中包含BottomSheets、BottomSheetDialog和BottomSheetDialogFragment三種可以使用。其中應(yīng)用較多的控件是BottomSheetDialog,主要運(yùn)用在界面底部分享列表,評(píng)論列表等,最近在知乎評(píng)論列表界面看到知乎運(yùn)用到了這個(gè)效果,所有在這里詳細(xì)介紹一下該控件的使用,以及簡(jiǎn)單實(shí)現(xiàn)知乎評(píng)論列表功能。本文實(shí)現(xiàn)效果如下:
首先我們想要使用BottomSheets相關(guān)控件,需要先在build.gradle中添加design依賴,本文中使用的是:
compile 'com.android.support:design:25.3.0'
BottomSheetDialog可以替代大多數(shù)網(wǎng)格顯示和列表展示的dialog和popupwindow,默認(rèn)寬度撐滿,并且在BottomSheetDialog 區(qū)域中向下滑動(dòng)也讓對(duì)話框消失。
接下來(lái)創(chuàng)建BottomSheetDialog的布局文件dialog_bottomsheet.xml,布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:id="@+id/dialog_bottomsheet_rl_title" android:layout_width="match_parent" android:layout_height="45dp" android:background="@drawable/dialog_bottomsheet_shape"> <ImageView android:id="@+id/dialog_bottomsheet_iv_close" android:layout_width="45dp" android:layout_height="45dp" android:layout_centerVertical="true" android:layout_marginLeft="5dp" android:padding="5dp" android:src="@drawable/img_close" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/dialog_bottomsheet_iv_close" android:text="評(píng)論" android:textColor="#333" android:textSize="16sp" /> </RelativeLayout> <android.support.v7.widget.RecyclerView android:id="@+id/dialog_bottomsheet_rv_lists" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/dialog_bottomsheet_rl_title" android:background="#fff" /> </RelativeLayout>
布局文件中,主要包含一個(gè)RecyclerView和一個(gè)頭布局。
然后,我們?cè)贏ctivity界面添加BottomSheetDailog初始化方法,
private void showSheetDialog() { View view = View.inflate(BottomSheetDialogActivity.this, R.layout.dialog_bottomsheet, null); iv_dialog_close = (ImageView) view.findViewById(R.id.dialog_bottomsheet_iv_close); rv_dialog_lists = (RecyclerView) view.findViewById(R.id.dialog_bottomsheet_rv_lists); iv_dialog_close.setOnClickListener(this); bottomSheetAdapter = new BottomSheetAdapter(BottomSheetDialogActivity.this, list_strs); rv_dialog_lists.setHasFixedSize(true); rv_dialog_lists.setLayoutManager(new LinearLayoutManager(BottomSheetDialogActivity.this)); rv_dialog_lists.setItemAnimator(new DefaultItemAnimator()); rv_dialog_lists.setAdapter(bottomSheetAdapter); bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog); bottomSheetDialog.setContentView(view); }
在改方法中,我們首先獲取BottomSheetDialog的布局文件,獲取該布局文件中相關(guān)控件,通過(guò)創(chuàng)建模擬列表數(shù)據(jù),為RecyclerView添加適配器
for (int i=0; i<20; i++) { list_strs.add("評(píng)論" + i); }
通過(guò)如下代碼,創(chuàng)建BottomSheetDialog對(duì)象
bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog); bottomSheetDialog.setContentView(view);
至此,我們即可以通過(guò)調(diào)用
bottomSheetDialog.show();
方法來(lái)查看BottomSheetDialog顯示效果
使用過(guò)程中出現(xiàn)的問(wèn)題
當(dāng)我們向下滑動(dòng)BottomSheetDialog隱藏Dialog后,無(wú)法用bottomSheetDialog.show()再次打開,為什么呢?我們先看下源碼的實(shí)現(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(); //關(guān)鍵代碼 } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } };
通過(guò)源碼文件我們可以看出,系統(tǒng)的BottomSheetDialog是基于BottomSheetBehavior封裝的,當(dāng)我們滑動(dòng)隱藏了BottomSheetBehavior中的View后,內(nèi)部是設(shè)置了BottomSheetBehavior的狀態(tài)為STATE_HIDDEN,接著它替我們關(guān)閉了Dialog,所以我們?cè)俅握{(diào)用show()的時(shí)候Dialog沒法再此打開狀態(tài)為HIDE的Dialog了。
查看了源文件,我們就通過(guò)復(fù)寫B(tài)ottomSheetCallback的回調(diào)方法,來(lái)實(shí)現(xiàn)我們的效果,這里就引入了BottomSheetBehavior,下面先介紹BottomSheetBehavior的使用。
BottomSheetBehavior的作用
根據(jù)官方Api,BottomSheetBehavior有一個(gè)靜態(tài)方法BottomSheetBehavior.from(View),會(huì)返回這個(gè)View引用的BottomSheetBehavior,這個(gè)方法會(huì)檢查這個(gè)View是否是CoordinatorLayout的子View,如果是就會(huì)得到這個(gè)View的Behavior。通過(guò)BottomSheetBehavior,我們可以通過(guò)setPeekHeight(int height)設(shè)置dialog的顯示高度,通過(guò)setBottomSheetCallback(callback)實(shí)現(xiàn)BottomSheetDialog的狀態(tài)監(jiān)聽。其中,在BottomSheetCallback回調(diào)方法中,onStateChanged監(jiān)聽狀態(tài)的改變,onSlide是拖拽的回調(diào),onStateChanged可以監(jiān)聽到的回調(diào)一共有五種:
- STATE_HIDDEN: 隱藏狀態(tài)。默認(rèn)是false,可通過(guò)app:behavior_hideable屬性設(shè)置。
- STATE_COLLAPSED: 折疊關(guān)閉狀態(tài)??赏ㄟ^(guò)app:behavior_peekHeight來(lái)設(shè)置顯示的高度,peekHeight默認(rèn)是0。
- STATE_DRAGGING: 被拖拽狀態(tài)
- STATE_SETTLING: 拖拽松開之后到達(dá)終點(diǎn)位置(collapsed or expanded)前的狀態(tài)。
- STATE_EXPANDED: 完全展開的狀態(tài)。
那么如何獲取到BottomSheetDialog的BottomSheetBehavior呢?
第一種:在BottomSheetDialog調(diào)用setContentView方法之后,調(diào)用
BottomSheetBehavior mDialogBehavior = BottomSheetBehavior.from((View) mContentView.getParent());
第二種:在BottomSheetDialog調(diào)用setContentView方法之后,調(diào)用
final FrameLayout frameLayout = (FrameLayout) dialog.findViewById(android.support.design.R.id.design_bottom_sheet); frameLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { frameLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); BottomSheetBehavior behavior = BottomSheetBehavior.from(frameLayout); //調(diào)用behavior相關(guān)方法 ... frameLayout.forceLayout(); }
通過(guò)上面的介紹,修改上文中的showSheetDialog()用于解決上文中出現(xiàn)的問(wèn)題,代碼如下:
private void showSheetDialog() { View view = View.inflate(BottomSheetDialogActivity.this, R.layout.dialog_bottomsheet, null); iv_dialog_close = (ImageView) view.findViewById(R.id.dialog_bottomsheet_iv_close); rv_dialog_lists = (RecyclerView) view.findViewById(R.id.dialog_bottomsheet_rv_lists); iv_dialog_close.setOnClickListener(this); bottomSheetAdapter = new BottomSheetAdapter(BottomSheetDialogActivity.this, list_strs); rv_dialog_lists.setHasFixedSize(true); rv_dialog_lists.setLayoutManager(new LinearLayoutManager(BottomSheetDialogActivity.this)); rv_dialog_lists.setItemAnimator(new DefaultItemAnimator()); rv_dialog_lists.setAdapter(bottomSheetAdapter); bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog); bottomSheetDialog.setContentView(view); mDialogBehavior = BottomSheetBehavior.from((View) view.getParent()); mDialogBehavior.setPeekHeight(getWindowHeight()); mDialogBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { bottomSheetDialog.dismiss(); mDialogBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); }
在監(jiān)聽到用戶滑動(dòng)關(guān)閉BottomSheetDialog后,我們把BottomSheetBehavior的狀態(tài)設(shè)置為BottomSheetBehavior.STATE_COLLAPSED,也就是半個(gè)打開狀態(tài)(BottomSheetBehavior.STATE_EXPANDED為全打開),至此就解決了調(diào)用show()方法無(wú)法正常打開的問(wèn)題。同時(shí)我們通過(guò)設(shè)置setPeekHeight和BottomSheetDialog的透明主題來(lái)實(shí)現(xiàn)知乎評(píng)論列表的效果。
在values/styles.xml文件中添加透明主題
<style name="dialog" parent="@android:style/Theme.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowIsFloating">true</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowNoTitle">true</item> <item name="android:background">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:backgroundDimEnabled">true</item> <item name="android:backgroundDimAmount">0.6</item> </style>
最后附上Activity界面完整代碼如下:
public class BottomSheetDialogActivity extends AppCompatActivity implements View.OnClickListener { private Button bt_start; private ImageView iv_dialog_close; private RecyclerView rv_dialog_lists; private BottomSheetAdapter bottomSheetAdapter; private BottomSheetDialog bottomSheetDialog; private BottomSheetBehavior mDialogBehavior; private List<String> list_strs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bottom_sheet_dialog); list_strs = new ArrayList<>(); initView(); showSheetDialog(); } private void initView() { bt_start = (Button) findViewById(R.id.main_bt_start); for (int i=0; i<20; i++) { list_strs.add("評(píng)論" + i); } bt_start.setOnClickListener(this); } private void showSheetDialog() { View view = View.inflate(BottomSheetDialogActivity.this, R.layout.dialog_bottomsheet, null); iv_dialog_close = (ImageView) view.findViewById(R.id.dialog_bottomsheet_iv_close); rv_dialog_lists = (RecyclerView) view.findViewById(R.id.dialog_bottomsheet_rv_lists); iv_dialog_close.setOnClickListener(this); bottomSheetAdapter = new BottomSheetAdapter(BottomSheetDialogActivity.this, list_strs); rv_dialog_lists.setHasFixedSize(true); rv_dialog_lists.setLayoutManager(new LinearLayoutManager(BottomSheetDialogActivity.this)); rv_dialog_lists.setItemAnimator(new DefaultItemAnimator()); rv_dialog_lists.setAdapter(bottomSheetAdapter); bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog); bottomSheetDialog.setContentView(view); mDialogBehavior = BottomSheetBehavior.from((View) view.getParent()); mDialogBehavior.setPeekHeight(getWindowHeight()); mDialogBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN) { bottomSheetDialog.dismiss(); mDialogBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); } private int getWindowHeight() { Resources res = BottomSheetDialogActivity.this.getResources(); DisplayMetrics displayMetrics = res.getDisplayMetrics(); return displayMetrics.heightPixels; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.main_bt_start: if (bottomSheetDialog != null) { bottomSheetDialog.show(); } break; case R.id.dialog_bottomsheet_iv_close: if (bottomSheetDialog != null) { bottomSheetDialog.dismiss(); } break; } } }
到此這篇關(guān)于android BottomSheetDialog新控件解析實(shí)現(xiàn)知乎評(píng)論列表效果的文章就介紹到這了,更多相關(guān)android 知乎評(píng)論列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Android如何設(shè)計(jì)一個(gè)全局可調(diào)用的ViewModel對(duì)象
很多時(shí)候我們需要維護(hù)一個(gè)全局可用的ViewModel,因?yàn)檫@樣可以維護(hù)全局同一份數(shù)據(jù)源,且方便使用協(xié)程綁定App的生命周期,那如何設(shè)計(jì)全局可用的ViewModel對(duì)象,文中介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05Android基于ViewPager實(shí)現(xiàn)的應(yīng)用歡迎界面完整實(shí)例
這篇文章主要介紹了Android基于ViewPager實(shí)現(xiàn)的應(yīng)用歡迎界面,結(jié)合完整實(shí)例形式分析了ViewPager類用于歡迎界面顯示圖片的具體步驟與相關(guān)操作技巧,需要的朋友可以參考下2016-08-08Android中BroadcastReceiver(異步接收廣播Intent)的使用
Broadcast Receiver是Android的五大組件之一,使用頻率也很高,用于異步接收廣播Intent,本文將詳細(xì)介紹,需要的朋友可以參考下2012-12-12Android 網(wǎng)絡(luò)狀態(tài)實(shí)時(shí)監(jiān)聽代碼實(shí)例(一)
本文給大家介紹Android 網(wǎng)絡(luò)狀態(tài)實(shí)時(shí)監(jiān)聽代碼實(shí)例(一),對(duì)android網(wǎng)絡(luò)狀態(tài)監(jiān)聽相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-03-03Android IPC機(jī)制ACtivity綁定Service通信代碼實(shí)例
這篇文章主要介紹了Android IPC機(jī)制ACtivity綁定Service通信代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Android判斷用戶2G/3G/4G移動(dòng)數(shù)據(jù)網(wǎng)絡(luò)
這篇文章主要介紹了Android判斷用戶2G/3G/4G移動(dòng)數(shù)據(jù)網(wǎng)絡(luò)的方法,感興趣的小伙伴們可以參考一下2015-12-12Android使用NestedScrollView?內(nèi)嵌RecycleView滑動(dòng)沖突問(wèn)題解決
這篇文章主要介紹了Android使用NestedScrollView?內(nèi)嵌RecycleView滑動(dòng)沖突問(wèn)題解決,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-06-06android編程實(shí)現(xiàn)添加文本內(nèi)容到sqlite表中的方法
這篇文章主要介紹了android編程實(shí)現(xiàn)添加文本內(nèi)容到sqlite表中的方法,結(jié)合實(shí)例較為詳細(xì)的分析了Android針對(duì)txt文本文件的讀取及SQL數(shù)據(jù)庫(kù)操作的相關(guān)技巧,需要的朋友可以參考下2015-11-11Android ListView之EfficientAdapte的使用詳解
這篇文章主要介紹了Android ListView之EfficientAdapte的使用詳解的相關(guān)資料,這里介紹EfficientAdapter 的使用方法,需要的朋友可以參考下2017-08-08