如何设置 Bottom Sheet peek height 以仅显示某些部分?
How to set Bottom Sheet peek height to show only certain parts initially?
假设我的底部 Sheet 有如下几行小部件。如果我最初只想显示前两行(即前两行 LinearLayout
s),而不显示下面的其余小部件。我不希望最初看到这些。如何设置正确的窥视高度? Hard-coding app:behavior_peekHeight
可能行不通,所以我需要通过编程来设置它,但是如何计算高度?
或者有没有更推荐的方法可以得到同样的结果?我的意思是,如果我测试 Google 地图,首先长按某个位置只会显示标题部分作为底部 sheet,但是当我尝试向上滚动底部 sheet 时,感觉如果标题部分(可能不是真正的底部 sheet)被包含所有元素的真正底部 sheet 替换。如果我的解释不够,请自己尝试 Google 地图。
<android.support.v4.widget.NestedScrollView
android:id="@+id/bottom_sheet"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView/>
<android.support.v7.widget.AppCompatSpinner/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView/>
<TextView/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView/>
<TextView/>
</LinearLayout>
<android.support.v7.widget.RecyclerView/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
我会用 ViewTreeObserver.OnGlobalLayoutListener
来解决这个问题,等待你的底部 sheet 被布置好,然后用第一个 y-coordinate 调用 BottomSheetBehavior.setPeekHeight()
您不想看到的视图。
private BottomSheetBehavior<View> behavior;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View bottomSheet = findViewById(R.id.bottomSheet);
behavior = BottomSheetBehavior.from(bottomSheet);
final LinearLayout inner = findViewById(R.id.inner);
inner.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
inner.getViewTreeObserver().removeOnGlobalLayoutListener(this);
View hidden = inner.getChildAt(2);
behavior.setPeekHeight(hidden.getTop());
}
});
}
在这种情况下,我的底部 sheet 是一个 NestedScrollView
持有一个 LinearLayout
,该 LinearLayout
持有许多 TextView
。通过将 peek 高度设置为第三个 TextView
的顶部(由 getChildAt(2)
获得),我的底部 sheet 在折叠时最终显示正好两个 TextView
。
自定义@Ben P. 的答案以将视图 ID 作为 peekHeight
的参考并创建函数:
/**
* Gets the bottom part of the target view and sets it as the peek height of the specified @{BottomSheetBehavior}
*
* @param layout - layout of the bottom sheet.
* @param targetViewId - id of the target view. Must be a view inside the 'layout' param.
* @param behavior - bottom sheet behavior recipient.
*/
private fun <T : ViewGroup> getViewBottomHeight(layout: ViewGroup,
targetViewId: Int,
behavior: BottomSheetBehavior<T>) {
layout.apply {
viewTreeObserver.addOnGlobalLayoutListener(
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
behavior.peekHeight = findViewById<View>(targetViewId).bottom
}
})
}
}
在我们的用例中,我们需要定位视图的 bottom 部分,所以我们这样设置。可以根据use-case.
进行调整
假设我的底部 Sheet 有如下几行小部件。如果我最初只想显示前两行(即前两行 LinearLayout
s),而不显示下面的其余小部件。我不希望最初看到这些。如何设置正确的窥视高度? Hard-coding app:behavior_peekHeight
可能行不通,所以我需要通过编程来设置它,但是如何计算高度?
或者有没有更推荐的方法可以得到同样的结果?我的意思是,如果我测试 Google 地图,首先长按某个位置只会显示标题部分作为底部 sheet,但是当我尝试向上滚动底部 sheet 时,感觉如果标题部分(可能不是真正的底部 sheet)被包含所有元素的真正底部 sheet 替换。如果我的解释不够,请自己尝试 Google 地图。
<android.support.v4.widget.NestedScrollView
android:id="@+id/bottom_sheet"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView/>
<android.support.v7.widget.AppCompatSpinner/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView/>
<TextView/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView/>
<TextView/>
</LinearLayout>
<android.support.v7.widget.RecyclerView/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
我会用 ViewTreeObserver.OnGlobalLayoutListener
来解决这个问题,等待你的底部 sheet 被布置好,然后用第一个 y-coordinate 调用 BottomSheetBehavior.setPeekHeight()
您不想看到的视图。
private BottomSheetBehavior<View> behavior;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View bottomSheet = findViewById(R.id.bottomSheet);
behavior = BottomSheetBehavior.from(bottomSheet);
final LinearLayout inner = findViewById(R.id.inner);
inner.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
inner.getViewTreeObserver().removeOnGlobalLayoutListener(this);
View hidden = inner.getChildAt(2);
behavior.setPeekHeight(hidden.getTop());
}
});
}
在这种情况下,我的底部 sheet 是一个 NestedScrollView
持有一个 LinearLayout
,该 LinearLayout
持有许多 TextView
。通过将 peek 高度设置为第三个 TextView
的顶部(由 getChildAt(2)
获得),我的底部 sheet 在折叠时最终显示正好两个 TextView
。
自定义@Ben P. 的答案以将视图 ID 作为 peekHeight
的参考并创建函数:
/**
* Gets the bottom part of the target view and sets it as the peek height of the specified @{BottomSheetBehavior}
*
* @param layout - layout of the bottom sheet.
* @param targetViewId - id of the target view. Must be a view inside the 'layout' param.
* @param behavior - bottom sheet behavior recipient.
*/
private fun <T : ViewGroup> getViewBottomHeight(layout: ViewGroup,
targetViewId: Int,
behavior: BottomSheetBehavior<T>) {
layout.apply {
viewTreeObserver.addOnGlobalLayoutListener(
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
behavior.peekHeight = findViewById<View>(targetViewId).bottom
}
})
}
}
在我们的用例中,我们需要定位视图的 bottom 部分,所以我们这样设置。可以根据use-case.
进行调整