Material Design系列之BottomSheet詳解
Material Design官方文檔Sheets: bottom的介紹
簡(jiǎn)介
BottomSheet可以理解為底部對(duì)話框音念,類似popwindow實(shí)現(xiàn)的效果
BottomSheet有兩種類型:
一躬翁、沒(méi)有蒙層姊途,可以對(duì)沒(méi)有遮蓋住的地方進(jìn)行操作贺辰,類似百度地圖查詢路線的頁(yè)面;
二、有蒙層效果,就是和正常的popwindow使用效果一樣了廊镜。
使用
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)
}
}