animateLayoutChanges ="真"在BottomSheetView中显示意外行为

时间:2017-02-07 10:40:34

标签: android android-layout android-fragments animation bottom-sheet

我的BottomSheetViewanimateLayoutChanges="true"。最初它显示很好。但是,如果将视图的visibilityBottomSheetView内)从GONE更改为VISIBLE,该应用会混乱计算,而我的BottomSheetView会移到顶部屏幕。我尝试在layout_gravity=bottom布局的根目录设置BottomSheetView。但没有成功。

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

enter image description here

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

enter image description here

我想,在计算视图widthheight的衡量标准时,Android正在搞乱。有什么方法可以解决这个问题吗?

我还试图让我的BottomSheetView完全扩展以匹配父视图,但不知何故,这使得height的{​​{1}}长于电话屏幕和插件创建滚动问题。

预期解决方案:

1>即使更改了视图的BottomSheetView,也可以防止BottomSheetView更改其位置。

OR

2>使visibility匹配父级,以便在弄乱计算后看起来不会很糟糕。

6 个答案:

答案 0 :(得分:7)

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

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

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

答案 1 :(得分:7)

BottomSheetBehavior暂时不能与LayoutTransitionanimateLayoutChanges="true")一起使用。我会努力修复。

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

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

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

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

答案 2 :(得分:1)

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

 android:layout_gravity="center_horizontal|top"

我真的不知道为什么底部 SheetDialog的重力位于顶部。

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

android:layout_gravity="center_horizontal|bottom"

答案 3 :(得分:1)

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

我终于有了一个解决方案,可以在拥有addView的同时将对removeViewanimateLayoutChanges="true"函数的调用保留在BottomSheet中。

BottomSheetBehavior更改后无法计算正确的高度,因此高度必须保持不变。为此,我将BottomSheet的高度设置为match_parent并将其分为两个子级:内容和一个Space,该内容根据内容的高度而改变高度。

要最好地模仿BottomSheet的真实行为,还需要添加一个TouchToDismiss视图,该视图在扩展BottomSheet时使背景变暗,而在扩展BottomSheet时也要关闭<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.xml

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);
}

activity.java

{{1}}

这是通过以下代码获得的结果: final result

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

答案 4 :(得分:0)

如果您的视图允许,请将可见性设置为 INVISIBLE 而不是 GONE。

答案 5 :(得分:0)

在我们的例子中,我们在按钮组件上显示了一个进度条。这是隐藏按钮文本并显示进度条。这导致底部片断的跳跃。使用 Invisible 而不是 Gone 解决了这个问题。