我正在使用Google最近发布的AppCompat v23.2中的BottomSheetBehavior
。我的底部工作表的高度取决于底部工作表内显示的内容(类似于Google在Google地图应用中的功能)。
最初加载的数据可以正常工作,但是我的应用程序更改了运行时显示的内容,当发生这种情况时,底部页面保留在旧的高度,这会导致底部未使用的空间或视图的切割。 / p>
有没有办法通知底部工作表布局重新计算用于展开状态的高度(当ViewGroup
的高度设置为MATCH_HEIGHT
时)或手动设置所需高度的任何方式?
编辑:我还尝试在invalidate()
及其父级上手动拨打ViewGroup
,但没有成功。
答案 0 :(得分:28)
我的问题与RelativeLayout
有同样的问题。高度不会被重新计算。我不得不求助于通过新重新计算的值设置高度并调用BottomSheetBehavior.onLayoutChild
。
这是我的临时解决方案:
coordinatorLayout = (CoordinatorLayout)findViewById(R.id.coordinator_layout);
bottomSheet = findViewById(R.id.bottom_sheet);
int accountHeight = accountTextView.getHeight();
accountTextView.setVisibility(View.GONE);
bottomSheet.getLayoutParams().height = bottomSheet.getHeight() - accountHeight;
bottomSheet.requestLayout();
behavior.onLayoutChild(coordinatorLayout, bottomSheet, ViewCompat.LAYOUT_DIRECTION_LTR);
答案 1 :(得分:9)
您可以使用BottomSheetBehavior#setPeekHeight
。
FrameLayout bottomSheet = (FrameLayout) findViewById(R.id.bottom_sheet);
BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setPeekHeight(newHeight);
这不会自动将底部工作表移动到窥视高度。您可以致电BottomSheetBehavior#setState
将底部工作表调整为新的峰值。
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
答案 2 :(得分:2)
虽然问题已在&gt; = 24.0.0支持库中得到解决,但如果由于某种原因您仍需要使用旧版本,则此处是一种解决方法。
mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull final View bottomSheet, int newState) {
bottomSheet.post(new Runnable() {
@Override
public void run() {
//workaround for the bottomsheet bug
bottomSheet.requestLayout();
bottomSheet.invalidate();
}
});
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
答案 3 :(得分:2)
有关底部对话框的片段,请阅读:Bottom Sheet Dialog Fragment Expand Full Height
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
FrameLayout bottomSheet = dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
behavior.setPeekHeight(0);
}
答案 4 :(得分:1)
我遇到了同样的问题,当尝试根据其内容更新峰值高度时,找到了之前布局的高度。这是有道理的,因为新的布局还没有发生。通过在UI线程上发布,在新布局之后计算布局高度,并且进行另一个布局请求以将底部工作表更新到正确的高度。
void show() {
setVisibility(View.VISIBLE);
post(new Runnable() {
@Override
public void run() {
mBottomSheetBehavior.setPeekHeight(findViewById(R.id.sheetPeek).getHeight());
requestLayout();
}
})
}
答案 5 :(得分:0)
当我在BottomSheet中使用recyclelerview并且项目动态更改时,我遇到了同样的问题。正如@sosite在他的评论中提到的那样,问题被记录下来并且他们已经在最新版本中修复了它。 Issue log here
只需将您的设计支持库更新到版本24.0.0并检查。
答案 6 :(得分:0)
我遵循@HaraldUnander的建议,它给了我一个切实可行的想法。如果以编程方式将BottomSheetBehavior.state
设置为STATE_COLLAPSED
后运行了一个线程(无法像他那样使用post方法工作),那么您已经可以获取视图的高度并将其设置为peekHeight
取决于其内容。
因此,首先设置BottomSheetBehavior
:
BottomSheetBehavior.from(routeCaptionBottomSheet).state = BottomSheetBehavior.STATE_COLLAPSED
然后您动态设置peekHeight:
thread {
activity?.runOnUiThread {
val dynamicHeight = yourContainerView.height
BottomSheetBehavior.from(bottomSheetView).peekHeight = dynamicHeight
}
}
如果使用Java(我将Kotlin和Anko一起用于线程),则可以这样做:
new Thread(new Runnable() {
public void run() {
val dynamicHeight = yourContainerView.height
BottomSheetBehavior.from(bottomSheetView).peekHeight = dynamicHeight
}
}).start();
答案 7 :(得分:0)
下面的代码段帮助我解决了这个问题,即我在布局的不同视图的可见性和高度之间的切换是自动改变的。
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.your_bottom_sheet_layout, container, false)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
dialog.setContentView(R.layout.your_bottom_sheet_layout)
dialog.setOnShowListener {
val castDialog = it as BottomSheetDialog
val bottomSheet = castDialog.findViewById<View?>(R.id.design_bottom_sheet)
val behavior = BottomSheetBehavior.from(bottomSheet)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
return dialog
}
答案 8 :(得分:0)
我一直在努力解决与您类似的问题。
手动设置bottomSheet的高度是我的解决方法。
具有一个具有BottomSheetBehaviour的视图 viewA 和一个用于修改视图高度的自定义方法 modifyHeight():
viewA?.modifyHeight()
viewA?.measure(
MeasureSpec.makeMeasureSpec(
width,
MeasureSpec.EXACTLY
),
MeasureSpec.makeMeasureSpec(
0,
MeasureSpec.UNSPECIFIED
)
)
val layoutParams = LayoutParams(viewA.measuredWidth, viewA.measuredHeight)
val bottomSheet = BottomSheetBehavior.from(viewA)
layoutParams.behavior = bottomSheet
viewA.layoutParams = layoutParams
我的布局如下:
<com.yourpackage.ViewA
android:id="@+id/viewA"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_peekHeight="50dp"
app:layout_behavior="@string/bottom_sheet_behavior" />
重用旧的layoutParams的bottomSheetBehaviour很重要,因为它包含您可能已附加的peekHeight和侦听器。
答案 9 :(得分:0)
这是我实现的切换按钮单击侦听器,用于设置带动画的底部工作表的拾取高度
FrameLayout standardBottomSheet = findViewById(R.id.standardBottomSheet);
BottomSheetBehavior<FrameLayout> bottomSheetBehavior = BottomSheetBehavior.from(standardBottomSheet);
btnToggleBottomSheet.setOnClickListener(new HPFM_OnSingleClickListener() {
@Override
public void onSingleClick(View v) {
if (bottomSheetBehavior.getPeekHeight() == 0) {
ObjectAnimator.ofInt(bottomSheetBehavior, "peekHeight", 200).setDuration(300).start();
}
else {
ObjectAnimator.ofInt(bottomSheetBehavior, "peekHeight", 0).setDuration(300).start();
}
}
});