Material Design组件 - 使用BottomSheet展现扩展内容(二)
上篇文章中我们使用在XML中配置bottom_sheet_behavior的方式实现了简单的BottomSheet,并说明了在XML中能够去配置的一些参数做了详细的说明,这篇文章我们会说明一下如何在代码中动态的去设置BottomSheet的一些行为
代码中动态设置BottomSheet
我们先来想一下,如果我们要实现一开始BottomSheet就是展开的状态,而不是折叠状态,那我们要怎么做呢?我们可以在代码中实现这个需求,代码很简单,如下
class OcrResultActivity : AppCompatActivity(R.layout.ocr_result_layout) {
val mBottomSheetBehavior: BottomSheetBehavior<View> by lazy {
BottomSheetBehavior.from(bottom_sheet)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
mBottomSheetBehavior.peekHeight = 200
}
}
我们使用BottomSheetBehavior类的from方法从我们页面上获取到我们的BottomSheetBehavior实例对象,然后我们就能对其进行各种各样的设置了,这边的设置包括了我们之前在xml的方式中能够配置的所有参数,并且这边还能设置BottomSheet的state,那么这个state又是什么呢?简单来说state就是说明当前BottomSheet的一个状态,其是展开还是折叠都属于其状态,有以下几种状态
- STATE_COLLAPSED:折叠状态,这个状态下BottomSheet会始终显示出来,高度的话会是peek height的高度
- STATE_EXPANDED:展开状态,在这个状态下,BottomSheet会展示其最大的高度
- STATE_HALF_EXPANDED:半展开状态,官网说明这个状态只有设置fitToContents为false时候才适用,但其实就算设置为true,使用代码方式修改BottomSheet的状态为STATE_HALF_EXPANDED的时候,也会触发这一状态
- STATE_HIDDEN:隐藏状态,这个状态下BottomSheet不可见,并且只能以代码设置的方式才能让其再次可见,经过试验,需要注意以下几点:
- 设置其hidden为true,将BottomSheet向下滑动变为隐藏状态后,再次动态设置其hidden为false会立即将BottomSheet再次展示,不需要重新设置其状态
- 设置其hidden为true,将BottomSheet向下滑动变为隐藏状态后,可设置其状态为STATE_COLLAPSED或STATE_HALF_EXPANDED或STATE_HALF_EXPANDED重新使其展现
- 可通过直接设置其状态为STATE_HIDDEN来直接隐藏BottomSheet
- STATE_DRAGGING:用户主动的向上或者向下拖动BottomSheet的时候
- STATE_SETTLING:这个状态是用户在拖动后,手指离开屏幕了,然而BottomSheet还在继续移动到指定高度的时候的那一小段时间即为这个状态,更像是STATE_COLLAPSED和STATE_HALF_EXPANDED的一个中间过渡状态
这边注意STATE_DRAGGING和STATE_SETTLING不能以代码方式进行设定,BottomSheet内部自行处理的,其余状态均可主动设置
我们可以给BottomSheetBehavior设置一个回调方法来接收上面的这些状态
mBottomSheetBehavior.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
Log.d("mBottomSheetBehavior", "newState = $newState")
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
-
onStateChanged方法会在状态改变的时候给你回调一个新的状态,我们就可以在这边做各种自己想要的处理,比如我们可以在每次展开的时候,都改变一下我们的BottomSheet背景颜色,就可以这样写
mBottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { when (newState) { BottomSheetBehavior.STATE_DRAGGING -> { val colorR = (0..255).random() val colorG = (0..255).random() val colorB = (0..255).random() bottomSheet.setBackgroundColor( Color.argb( 255, colorR, colorG, colorB ) ) } else -> {} } } override fun onSlide(bottomSheet: View, slideOffset: Float) { } })
效果如下:
- onSlide方法就更为有用了,其slideOffset是一个比例,其值从-1到0到1,0到1说明的是BottomSheet在滑动过程中,从折叠状态到完全展开状态的中间过程的一个比例,折叠状态为0,向上滑动会不断的从0变大,直到完全展开状态变为1为止,0到-1说明了BottomSheet在从折叠状态向隐藏状态滑动的一个比例,-1即说明BottomSheet被隐藏了,该回调在直接设置BottomSheet状态使BottomSheet展开或者折叠的过程中,会有多次的回调,返回的是一个过程性的比例关系,大家可以亲自试一下就知道了,这边不再过多展示了,之后会有一个实战Demo中会用到这个来做一些效果
模态BottomSheet
自此,BottomSheet的状态我们也都了解清楚了,那么也许有人会有另一种需求,即我想要那种和Dialog一样的,后面有蒙版的,专业点叫模态窗口哈,官方也很贴心,为我们直接提供了BottomSheetDialog和BottomSheetDialogFragment,其实这两个就是将BottomSheetBehavior与Dialog相结合的产物,用法也相当简单,我们有了前面的基础,再看这个就简单多了哈
BottomSheetDialog
我们先来看一个BottomSheetDialog的简单用法
class ModalBottomActivity : AppCompatActivity(R.layout.ocr_result_layout) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bsd = BottomSheetDialog(this)
bsd.setContentView(R.layout.modal_buttom_sheet_content)
bsd.behavior.peekHeight = 200
// bsd.behavior.isHideable = false //注意,这边BottomSheetDialog默认的hideable行为是true,与BottomSheetBehavior不同,毕竟Dialog默认就是应该可以隐藏才对
bsd.show()
button_1.setOnClickListener {
bsd.show()
}
}
}
BottomSheetDialog内部给我们创建了BottomSheetBehavior,所以我们不需要关心BottomSheetBehavior,直接使用即可,XML中我们也只需要实现我们自己的布局即可,XML中的布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="aaaaaaaaaaaaaaabbbbbbbbbbbbbccccccccccccc"
/>
</LinearLayout>
这样,我们的BottomSheetDialog就显示出来了,看看效果
你也可以继承BottomSheetDialog和普通Dialog的用法一样,来自定义你自己的Dialog,其行为和Dialog几乎一样的,所以这边只是简单演示一下,其余的就不在这边细说了
BottomSheetDialogFragment
接下来我们来看一下BottomSheetDialogFragment,这个Fragment内部给我们创建了BottomSheetDialog,所以我们用起来可以更加的方便,代码如下
class ModalBottomActivity : AppCompatActivity(R.layout.ocr_result_layout) {
val modalBottomSheet = ModalBottomSheet()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
modalBottomSheet.show(supportFragmentManager, ModalBottomSheet.TAG)
button_1.setOnClickListener {
modalBottomSheet.show(supportFragmentManager, ModalBottomSheet.TAG)
}
}
}
class ModalBottomSheet : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(
R.layout.modal_buttom_sheet_content,
container,
false
)
companion object {
const val TAG = "ModalBottomSheet"
}
}
这样我们就实现了BottomSheetDialogFragment的展现,另外,我们如果想要对BottomSheet进行设置的话,可以这样获取BottomSheetBehavior对象,就能够自由的进行设置了
class ModalBottomSheet : BottomSheetDialogFragment() {
lateinit var behavior: BottomSheetBehavior<FrameLayout>
override fun onCreateView ...
//注意需要在onStart的时候才能正常获取到BottomSheetBehavior
override fun onStart() {
super.onStart()
val bottomSheet: FrameLayout =
dialog?.findViewById(R.id.design_bottom_sheet) ?: return
behavior = BottomSheetBehavior.from(bottomSheet)
behavior.peekHeight = 400
}
companion object {
const val TAG = "ModalBottomSheet"
}
}
好了,BottomSheet的基本使用已经都说完了,大家理解了吗?另外,在最后推荐给大家一个非常好的类似BottomSheet效果的第三方库SlidingUpPanelLayout,大家可以了解下并尝试使用下,看看哪个更适合你自己的需求,再来选择使用
下回我们会用一个Demo来让BottomSheet嵌套一个列表来实现更好的效果,希望大家喜欢
最后还望各位兄弟姐妹们点个赞,关个注,更多的我理解的内容我还会陆续和大家分享的,谢谢大家!