动态更改BottomSheetBehavior的高度

时间:2016-02-28 17:17:54

标签: android android-appcompat appcompat-v7-r23.2

我正在使用Google最近发布的AppCompat v23.2中的BottomSheetBehavior。我的底部工作表的高度取决于底部工作表内显示的内容(类似于Google在Google地图应用中的功能)。

最初加载的数据可以正常工作,但是我的应用程序更改了运行时显示的内容,当发生这种情况时,底部页面保留在旧的高度,这会导致底部未使用的空间或视图的切割。 / p>

有没有办法通知底部工作表布局重新计算用于展开状态的高度(当ViewGroup的高度设置为MATCH_HEIGHT时)或手动设置所需高度的任何方式?

编辑:我还尝试在invalidate()及其父级上手动拨打ViewGroup,但没有成功。

10 个答案:

答案 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();
                    }
                }
            });