1. 程式人生 > 程式設計 >android BottomSheetDialog新控制元件解析實現知乎評論列表效果(例項程式碼)

android BottomSheetDialog新控制元件解析實現知乎評論列表效果(例項程式碼)

BottomSheetDialog使用解析

Android Support Library 23.2裡的 Design Support Library新加了一個Bottom Sheets控制元件,Bottom Sheets顧名思義就是底部操作控制元件,用於在螢幕底部建立一個可滑動關閉的檢視,可以替代對話方塊和選單。其中包含BottomSheets、BottomSheetDialog和BottomSheetDialogFragment三種可以使用。其中應用較多的控制元件是BottomSheetDialog,主要運用在介面底部分享列表,評論列表等,最近在知乎評論列表介面看到知乎運用到了這個效果,所有在這裡詳細介紹一下該控制元件的使用,以及簡單實現知乎評論列表功能。本文實現效果如下:

這裡寫圖片描述

首先我們想要使用BottomSheets相關控制元件,需要先在build.gradle中新增design依賴,本文中使用的是:

compile 'com.android.support:design:25.3.0'

BottomSheetDialog可以替代大多數網格顯示和列表展示的dialog和popupwindow,預設寬度撐滿,並且在BottomSheetDialog 區域中向下滑動也讓對話方塊消失。

接下來建立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="評論"
 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>

佈局檔案中,主要包含一個RecyclerView和一個頭佈局。

然後,我們在Activity介面新增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的佈局檔案,獲取該佈局檔案中相關控制元件,通過建立模擬列表資料,為RecyclerView新增介面卡

for (int i=0; i<20; i++) {
 list_strs.add("評論" + i);
 }

通過如下程式碼,建立BottomSheetDialog物件

bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this,R.style.dialog);
bottomSheetDialog.setContentView(view);

至此,我們即可以通過呼叫

bottomSheetDialog.show();

方法來檢視BottomSheetDialog顯示效果

使用過程中出現的問題

當我們向下滑動BottomSheetDialog隱藏Dialog後,無法用bottomSheetDialog.show()再次開啟,為什麼呢?我們先看下原始碼的實現:

@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) {
 }
};

通過原始碼檔案我們可以看出,系統的BottomSheetDialog是基於BottomSheetBehavior封裝的,當我們滑動隱藏了BottomSheetBehavior中的View後,內部是設定了BottomSheetBehavior的狀態為STATE_HIDDEN,接著它替我們關閉了Dialog,所以我們再次呼叫show()的時候Dialog沒法再此開啟狀態為HIDE的Dialog了。
查看了原始檔,我們就通過複寫BottomSheetCallback的回撥方法,來實現我們的效果,這裡就引入了BottomSheetBehavior,下面先介紹BottomSheetBehavior的使用。

BottomSheetBehavior的作用

根據官方Api,BottomSheetBehavior有一個靜態方法BottomSheetBehavior.from(View),會返回這個View引用的BottomSheetBehavior,這個方法會檢查這個View是否是CoordinatorLayout的子View,如果是就會得到這個View的Behavior。通過BottomSheetBehavior,我們可以通過setPeekHeight(int height)設定dialog的顯示高度,通過setBottomSheetCallback(callback)實現BottomSheetDialog的狀態監聽。其中,在BottomSheetCallback回撥方法中,onStateChanged監聽狀態的改變,onSlide是拖拽的回撥,onStateChanged可以監聽到的回撥一共有五種:

  • STATE_HIDDEN: 隱藏狀態。預設是false,可通過app:behavior_hideable屬性設定。
  • STATE_COLLAPSED: 摺疊關閉狀態。可通過app:behavior_peekHeight來設定顯示的高度,peekHeight預設是0。
  • STATE_DRAGGING: 被拖拽狀態
  • STATE_SETTLING: 拖拽鬆開之後到達終點位置(collapsed or expanded)前的狀態。
  • STATE_EXPANDED: 完全展開的狀態。

那麼如何獲取到BottomSheetDialog的BottomSheetBehavior呢?

第一種:在BottomSheetDialog呼叫setContentView方法之後,呼叫

BottomSheetBehavior mDialogBehavior = BottomSheetBehavior.from((View) mContentView.getParent());

第二種:在BottomSheetDialog呼叫setContentView方法之後,呼叫

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);

 //呼叫behavior相關方法
 ... 

 frameLayout.forceLayout();

}

通過上面的介紹,修改上文中的showSheetDialog()用於解決上文中出現的問題,程式碼如下:

private void showSheetDialog() {
 View view = View.inflate(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) {
 }
 });
 }

在監聽到使用者滑動關閉BottomSheetDialog後,我們把BottomSheetBehavior的狀態設定為BottomSheetBehavior.STATE_COLLAPSED,也就是半個開啟狀態(BottomSheetBehavior.STATE_EXPANDED為全開啟),至此就解決了呼叫show()方法無法正常開啟的問題。同時我們通過設定setPeekHeight和BottomSheetDialog的透明主題來實現知乎評論列表的效果。
在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("評論" + i);
 }

 bt_start.setOnClickListener(this);
 }

 private void showSheetDialog() {
 View view = View.inflate(BottomSheetDialogActivity.this,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;
 }
 }
}

到此這篇關於android BottomSheetDialog新控制元件解析實現知乎評論列表效果的文章就介紹到這了,更多相關android 知乎評論列表內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!