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

Sru*_*rai 19 animation android android-layout android-fragments bottom-sheet

我有一个BottomSheetView具有animateLayoutChanges="true".最初它显示很好.但如果将visibility视图(内部BottomSheetView)更改GONEVISIBLE,则应用程序会混乱计算并BottomSheetView移动到屏幕顶部.我试过设置布局layout_gravity=bottom的根目录BottomSheetView.但没有成功.

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

在此输入图像描述

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

在此输入图像描述

我猜,Android在计算视图width和测量时会搞乱height.有什么办法解决这个问题?

我也试图让我的BottomSheetView完全延伸至父视图匹配,但不知何故,即拍即heightBottomSheetView比手机屏幕和-TUN创建滚动问题更长.

预期的解决方案:

1> BottomSheetView即使visibility视图改变,也要防止改变其位置.

要么

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

Yui*_*aki 11

BottomSheetBehavior现在不适用于LayoutTransition(animateLayoutChanges="true").我会努力修复.

现在,您可以Transition改用.这样的东西会淡化内部视图并使底部工作表的大小生动.

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

TransitionManager.beginDelayedTransition(bottomSheet);
hidingView.setVisibility(View.GONE);
Run Code Online (Sandbox Code Playgroud)

您可以参考应用转换以获取更多信息,包括如何自定义动画.

  • 自报告此问题以来已经过去 4 年了,2021 年该问题仍然存在 (4认同)
  • 对于那些尝试对 BottomSheetDialog 的内容更改进行动画处理的人 - 您必须找到工作表视图组,例如“dialog.findViewById<ViewGroup>(com.google.android.material.R.id.design_bottom_sheet)” (3认同)
  • 完美的解决方案。此外,例如,如果想要更改持续时间,请将以下转换添加为“beginDelayedTransition”的第二个参数:“new AutoTransition().setDuration(150)” (2认同)
  • 那么这是解决办法吗?我正在使用库“com.android.support:design”的最新版本,并且仍在发生..检查此处:https://github.com/extmkv/BottomSheetExample (2认同)

Ala*_*ifa 11

我用这个,我必须保留动画!

 val transition = LayoutTransition()
 transition.setAnimateParentHierarchy(false)
 {Parent View which has animateLayoutChanges="true" }.layoutTransition = transition
Run Code Online (Sandbox Code Playgroud)


小智 8

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

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

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

  • 你提交了这个bug吗?你找到了一个优雅的方式吗? (4认同)

Cha*_*nic 7

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

我终于找到了一个解决方案addViewremoveView可以在 BottomSheet 中保留对和函数的调用,同时具有animateLayoutChanges="true".

BottomSheetBehavior改变时无法计算正确的高度,因此高度必须保持不变。为此,我设置BottomSheetto的高度match_parent并将其分成两个子项:内容和Space根据内容高度改变高度的a 。

为了最好地模仿 a 的真实行为BottomSheet,您还需要添加一个 TouchToDismiss 视图,该视图在BottomSheet扩展时使背景变暗,但BottomSheet在用户按下内容外部时关闭。

这是代码:

活动.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>
Run Code Online (Sandbox Code Playgroud)

活动.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);
}
Run Code Online (Sandbox Code Playgroud)

这是使用此代码获得的结果: 最后结果

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