Android底部Sheet
在本教程中,我们将讨论并实现随Android支持v23.2一起引入的android底表小部件。
Android底部Sheet
根据Google材料设计文档;
底页是从屏幕底部边缘向上滑动的页。
由于用户触发了操作,因此显示底页,并且通过向上滑动也可以显示其他内容。
底页可以是模式的(从屏幕底部向上滑动以显示更多内容),也可以是固定的(与应用集成以显示支持内容时)。
BottomSheets可以实现为BottomSheetBehavior
,BottomSheetDialog
和BottomSheetDialogFragment
。
Android BottomSheet行为
BottomSheetBehavior是用于持久性底部工作表的一种" layout_behavior"。
它需要将CoordinatorLayout设置为该布局的根元素,并向子视图添加xml属性ʻapp:layout_behavior:android.support.design.widget.BottomSheetBehavior`。
让我们看一下将放置在CoordinatorLayout中的示例xml子视图。
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" app:behavior_hideable="false" app:behavior_peekHeight="120dp" android:orientation="vertical" app:layout_behavior="@string/bottom_sheet_behavior"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/lorem_ipsum" </LinearLayout>
从以上代码片段中得出的结论很少:
- layout_behavior将视图设置为底页
- behavior_peekHeight设置工作表的可见部分
- behavior_hideable设置是否可以通过进一步向下拖动视图来隐藏该视图。
它接受布尔值。
让我们在Android Studio中创建一个新项目,将模板设置为"基本活动",然后在" activity_main.xml"中的xml片段上方添加。
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.theitroad.bottomsheet.MainActivity"> <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" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:src="@android:drawable/ic_dialog_email" <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" app:behavior_hideable="false" app:behavior_peekHeight="120dp" android:orientation="vertical" app:layout_behavior="@string/bottom_sheet_behavior"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/lorem_ipsum" </LinearLayout> </android.support.design.widget.CoordinatorLayout>
让我们运行一次应用程序,看看它的行为。
设置app:behavior_hideable =" true",一旦向下拖动,底部工作表将保持隐藏状态。
" BottomSheetBehavior"类允许我们以编程方式设置视图的当前状态。
以下是用于处理状态的重要常量:
STATE_COLLAPSED:使用在peekHeight属性上设置的值来设置底部工作表的高度。
STATE_DRAGGING:正在拖动底部的工作表
STATE_EXPANDED:底部工作表已完全展开
STATE_HIDDEN:底部工作表从屏幕上完全隐藏
让我们跳到本教程的业务端。
我们将开发一个应用程序,该应用程序在底部的表格内显示一个RecyclerView以及可供选择的项目。
Android底表示例项目结构
Android底表示例代码
下面定义了" activity_main.xml"布局。
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:id="@+id/coordinatorLayout" tools:context="com.theitroad.bottomsheet.MainActivity"> <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" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" android:orientation="vertical" app:behavior_hideable="true" app:behavior_peekHeight="0dp" android:id="@+id/bottom_sheet" android:background="@android:color/white" app:layout_behavior="@string/bottom_sheet_behavior"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:textStyle="bold" android:text="SELECT AN ITEM" <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginTop="16dp" </LinearLayout> </android.support.design.widget.CoordinatorLayout>
MainActivity.java在下面给出。
package com.theitroad.bottomsheet; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Button; import java.util.ArrayList; public class MainActivity extends AppCompatActivity implements ItemAdapter.ItemListener { BottomSheetBehavior behavior; RecyclerView recyclerView; private ItemAdapter mAdapter; CoordinatorLayout coordinatorLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout); View bottomSheet = findViewById(R.id.bottom_sheet); behavior = BottomSheetBehavior.from(bottomSheet); behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { //React to state change } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { //React to dragging events } }); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); ArrayList items = new ArrayList(); items.add("Item 1"); items.add("Item 2"); items.add("Item 3"); items.add("Item 4"); items.add("Item 5"); items.add("Item 6"); mAdapter = new ItemAdapter(items, this); recyclerView.setAdapter(mAdapter); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { behavior.setState(BottomSheetBehavior.STATE_EXPANDED); } }); } @Override public void onItemClick(String item) { Snackbar.make(coordinatorLayout,item + " is selected", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); behavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } }
以下是从上面的代码得出的推论。
behavior = BottomSheetBehavior.from(bottomSheet); from(View view)是BottomSheetBehavior类的静态方法,用于从View实例的布局参数中获取行为的实例。
在BottomSheetBehavior实例上调用BottomSheetCallback,以便我们接收底部工作表的回调,例如状态更改和偏移量更改。
ItemAdapter.java类具有RecyclerView适配器的实现,如下所示。
package com.theitroad.bottomsheet; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; class ItemAdapter extends RecyclerView.Adapter { private List mItems; private ItemListener mListener; ItemAdapter(List items, ItemListener listener) { mItems = items; mListener = listener; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new ViewHolder(LayoutInflater.from(parent.getContext()) .inflate(R.layout.bottom_sheet_item, parent, false)); } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.setData(mItems.get(position)); } @Override public int getItemCount() { return mItems.size(); } class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView textView; String item; ViewHolder(View itemView) { super(itemView); itemView.setOnClickListener(this); textView = (TextView) itemView.findViewById(R.id.textView); } void setData(String item) { this.item = item; textView.setText(item); } @Override public void onClick(View v) { if (mListener != null) { mListener.onItemClick(item); } } } interface ItemListener { void onItemClick(String item); } }
上面的代码与我们之前在RecyclerView教程中实现的代码相似,但您所看到的界面除外。
该接口是在MainActivity.java类中实现的,目的是使RecyclerView的onItemClick功能类似于ListView。
回到MainActivity.java类,
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
展开底部工作表。
单击RecyclerView项将显示SnackBar并折叠底部表。
让我们看看实际的应用程序。
在上面的输出中,我们可以看到可以将BottomSheet向下拖动而无需选择项目。
为防止未选择任何项目而使其塌陷,请将BottomSheetCallBack设置为:
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_DRAGGING) { behavior.setState(BottomSheetBehavior.STATE_EXPANDED); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { //React to dragging events } });