我有一个BottomSheetView
有animateLayoutChanges="true"
。最初它显示很好。但如果将visibility
中的BottomSheetView
视图(GONE
内部)更改为VISIBLE
,应用程序会混乱计算,我的BottomSheetView
会移动到屏幕顶部。我试过在layout_gravity=bottom
布局的根部设置BottomSheetView
。但没有成功。
在改变任何视图的可见性之前,我有BottomSheetView
的图像。 (点击图片查看完整尺寸)
在我更改视图(GONE
到VISIBLE
或VISIBLE
到GONE
)的可见性后,我的BottomSheetView移动到顶部。 (点击图片查看完整尺寸)
我想,在计算视图width
和height
的计算时,Android正在搞乱。有什么办法解决这个问题?
我还尝试使我的BottomSheetView完全扩展以匹配父视图,但不知何故,这使得height
的BottomSheetView
比电话屏幕更长,并且内部创建滚动问题。
预期的解决方案:
1>即使视图的BottomSheetView
发生变化,也可防止visibility
改变其位置。
要么
2>使BottomSheetView
匹配父级,以便在弄乱计算后看起来不坏。
我遇到了同样的问题,并决定找到一个解决方案。我能够找到根本原因,但遗憾的是我目前看不到很好的修复。
原因:底部表格行为和LayoutTransition之间出现问题。创建LayoutTransition时,它会在视图上创建一个OnLayoutChangeListener,以便它可以捕获其endValues并使用正确的值设置动画师。这个OnLayoutChangeListener在它首次调用onLayout()
时在bottomSheetBehavior的parent.onLayout(child)
调用中被触发。父级将像往常一样布局子级,忽略行为稍后会改变的任何偏移。问题出在这里。此时视图的值由OnLayoutChangeListener捕获并存储在动画制作器中。动画运行时,它将为这些值设置动画,而不是您的行为定义的位置。不幸的是,LayoutTransition类不允许我们访问动画师以允许更新结束值。
修复:目前,我没有看到涉及LayoutTransitions的优雅修复。我将提交一个访问和更新LayoutTransition动画师的方法的bug。现在,您可以使用layoutTransition.setAnimateParentHierachy(false)
禁用父容器上的任何layoutTransition。然后,您可以自己动画更改。我会尽快用一个有效的例子来更新我的答案。
截至目前,BottomSheetBehavior与LayoutTransition
(animateLayoutChanges="true"
)的效果不佳。我会努力修复。
现在,您可以使用Transition
代替。这样的东西会使内部视图褪色并使底部纸张的大小生动。
ViewGroup bottomSheet = ...;
View hidingView = ...;
TransitionManager.beginDelayedTransition(bottomSheet);
hidingView.setVisibility(View.GONE);
您可以参考Applying a Transition以获取更多信息,包括如何自定义动画。
这个问题是在两年多前提出的,但不幸的是问题仍然存在。
我终于得到了一个解决方案来保持对底部表格中的addView
和removeView
函数的调用,同时拥有animateLayoutChanges="true"
。
BottomSheetBehavior
在更改时无法计算正确的高度,因此高度必须保持不变。为此,我将BottomSheet
的高度设置为match_parent
并将其分为两个子项:内容和根据内容高度改变高度的Space
。
为了最好地模仿BottomSheet
的真实行为,你还需要添加一个TouchToDismiss视图,当BottomSheet
被扩展时会使背景变暗,但当用户按下内容时也会关闭BottomSheet
。
这是代码:
activity.xml
<androidx.coordinatorlayout.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"
tools:context=".MainActivity">
<Button
android:id="@+id/show_bottom_sheet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show bottom sheet"/>
<View
android:id="@+id/touch_to_dismiss"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:background="#9000"/>
<LinearLayout
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<Space
android:id="@+id/space"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/bottom_sheet_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true">
<Button
android:id="@+id/add_or_remove_another_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add another view"/>
<TextView
android:id="@+id/another_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Another view"/>
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
activity.Java
BottomSheetBehavior bottomSheetBehavior;
View touchToDismiss;
LinearLayout bottomSheet;
Button showBottomSheet;
Space space;
LinearLayout bottomSheetContent;
Button addOrRemoveAnotherView;
TextView anotherView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
touchToDismiss = findViewById(R.id.touch_to_dismiss);
touchToDismiss.setVisibility(View.GONE);
touchToDismiss.setOnClickListener(this);
bottomSheet = findViewById(R.id.bottom_sheet);
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setPeekHeight(0);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN || newState == BottomSheetBehavior.STATE_COLLAPSED) {
touchToDismiss.setVisibility(View.GONE);
}else {
touchToDismiss.setVisibility(View.VISIBLE);
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
touchToDismiss.setAlpha(getRealOffset());
}
});
showBottomSheet = findViewById(R.id.show_bottom_sheet);
showBottomSheet.setOnClickListener(this);
space = findViewById(R.id.space);
bottomSheetContent = findViewById(R.id.bottom_sheet_content);
addOrRemoveAnotherView = findViewById(R.id.add_or_remove_another_view);
addOrRemoveAnotherView.setOnClickListener(this);
anotherView = findViewById(R.id.another_view);
bottomSheetContent.removeView(anotherView);
}
@Override
public void onClick(View v) {
if (v == showBottomSheet)
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
else if (v == addOrRemoveAnotherView) {
if (anotherView.getParent() == null)
bottomSheetContent.addView(anotherView);
else
bottomSheetContent.removeView(anotherView);
}
else if (v == touchToDismiss)
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
/**
* Since the height does not change and remains at match_parent, it is required to calculate the true offset.
* @return Real offset of the BottomSheet content.
*/
public float getRealOffset() {
float num = (space.getHeight() + bottomSheetContent.getHeight()) - (bottomSheet.getY() + space.getHeight());
float den = bottomSheetContent.getHeight();
return (num / den);
}
希望它对某人有用,因为问题仍然存在!
在BottomSheetDialog默认布局(design_bottom_sheet_dialog)中,对话框的design_bottom_sheet
FrameLayout上有一个TOP重力:
android:layout_gravity="center_horizontal|top"
我真的不知道为什么BottomSheetDialog引力是最重要的。
您需要在项目中创建相同的布局文件(相同的内容和名称),并将此行替换为:
android:layout_gravity="center_horizontal|bottom"