BottomSheetView中的animateLayoutChanges =“true”显示意外行为

问题描述 投票:15回答:4

我有一个BottomSheetViewanimateLayoutChanges="true"。最初它显示很好。但如果将visibility中的BottomSheetView视图(GONE内部)更改为VISIBLE,应用程序会混乱计算,我的BottomSheetView会移动到屏幕顶部。我试过在layout_gravity=bottom布局的根部设置BottomSheetView。但没有成功。

在改变任何视图的可见性之前,我有BottomSheetView的图像。 (点击图片查看完整尺寸)

enter image description here

在我更改视图(GONEVISIBLEVISIBLEGONE)的可见性后,我的BottomSheetView移动到顶部。 (点击图片查看完整尺寸)

enter image description here

我想,在计算视图widthheight的计算时,Android正在搞乱。有什么办法解决这个问题?

我还尝试使我的BottomSheetView完全扩展以匹配父视图,但不知何故,这使得heightBottomSheetView比电话屏幕更长,并且内部创建滚动问题。

预期的解决方案:

1>即使视图的BottomSheetView发生变化,也可防止visibility改变其位置。

要么

2>使BottomSheetView匹配父级,以便在弄乱计算后看起来不坏。

android android-layout android-fragments animation bottom-sheet
4个回答
7
投票

我遇到了同样的问题,并决定找到一个解决方案。我能够找到根本原因,但遗憾的是我目前看不到很好的修复。

原因:底部表格行为和LayoutTransition之间出现问题。创建LayoutTransition时,它会在视图上创建一个OnLayoutChangeListener,以便它可以捕获其endValues并使用正确的值设置动画师。这个OnLayoutChangeListener在它首次调用onLayout()时在bottomSheetBehavior的parent.onLayout(child)调用中被触发。父级将像往常一样布局子级,忽略行为稍后会改变的任何偏移。问题出在这里。此时视图的值由OnLayoutChangeListener捕获并存储在动画制作器中。动画运行时,它将为这些值设置动画,而不是您的行为定义的位置。不幸的是,LayoutTransition类不允许我们访问动画师以允许更新结束值。

修复:目前,我没有看到涉及LayoutTransitions的优雅修复。我将提交一个访问和更新LayoutTransition动画师的方法的bug。现在,您可以使用layoutTransition.setAnimateParentHierachy(false)禁用父容器上的任何layoutTransition。然后,您可以自己动画更改。我会尽快用一个有效的例子来更新我的答案。


7
投票

截至目前,BottomSheetBehavior与LayoutTransitionanimateLayoutChanges="true")的效果不佳。我会努力修复。

现在,您可以使用Transition代替。这样的东西会使内部视图褪色并使底部纸张的大小生动。

ViewGroup bottomSheet = ...;
View hidingView = ...;

TransitionManager.beginDelayedTransition(bottomSheet);
hidingView.setVisibility(View.GONE);

您可以参考Applying a Transition以获取更多信息,包括如何自定义动画。


1
投票

这个问题是在两年多前提出的,但不幸的是问题仍然存在。

我终于得到了一个解决方案来保持对底部表格中的addViewremoveView函数的调用,同时拥有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);
}

这是使用以下代码获得的结果:final result

希望它对某人有用,因为问题仍然存在!


0
投票

在BottomSheetDialog默认布局(design_bottom_sheet_dialog)中,对话框的design_bottom_sheet FrameLayout上有一个TOP重力:

 android:layout_gravity="center_horizontal|top"

我真的不知道为什么BottomSheetDialog引力是最重要的。

您需要在项目中创建相同的布局文件(相同的内容和名称),并将此行替换为:

android:layout_gravity="center_horizontal|bottom"
© www.soinside.com 2019 - 2024. All rights reserved.