animateLayoutChanges="true"
を持つBottomSheetView
があります。最初は問題なく表示されます。しかし、ビュー(visibility
内)のBottomSheetView
をGONE
からVISIBLE
に変更すると、アプリは計算と私のBottomSheetView
を台無しにします。画面の上部に移動します。 BottomSheetView
レイアウトのルートにlayout_gravity=bottom
を設定してみました。しかし、成功しません。
ここに、ビューの表示を変更する前のBottomSheetView
の画像があります。 (フルサイズは画像をクリックしてください)
ビューの表示を変更した後(GONE
からVISIBLE
またはVISIBLE
からGONE
)、BottomSheetViewが一番上に移動します。 (フルサイズは画像をクリックしてください)
おそらく、Androidはビューwidth
とheight
の測定について計算をしているときに混乱しています。これを解決する方法はありますか?
また、BottomSheetViewを完全に拡張して親ビューに一致させようとしましたが、どういうわけか、height
のBottomSheetView
が電話の画面よりも長くなり、スクロールの問題が発生します。
期待される解決策:
1>ビューのBottomSheetView
が変更された場合でも、visibility
がその位置を変更しないようにします。
OR
2> BottomSheetView
を親に一致させて、計算を台無しにした後に見栄えが悪くならないようにします。
BottomSheetBehaviorはLayoutTransition
(animateLayoutChanges="true"
) 今のところ。修正に取り組みます。
今のところ、代わりにTransition
を使用できます。このようなものは、内部のビューをフェードさせ、下部シートのサイズをアニメーション化します。
ViewGroup bottomSheet = ...;
View hidingView = ...;
TransitionManager.beginDelayedTransition(bottomSheet);
hidingView.setVisibility(View.GONE);
アニメーションのカスタマイズ方法などの詳細については、 トランジションの適用 を参照してください。
私は同じ問題に遭遇し、修正を見つけることを決心しました。根本的な原因を見つけることができましたが、残念ながら現時点では大きな解決策は見当たりません。
原因:問題はボトムシートの動作とLayoutTransitionの間で発生します。 LayoutTransitionが作成されると、ビューにOnLayoutChangeListenerが作成され、endValuesをキャプチャして、適切な値でアニメーターをセットアップできるようになります。このOnLayoutChangeListenerは、bottomSheetBehaviorのonLayout()
呼び出しで、最初にparent.onLayout(child)
を呼び出したときにトリガーされます。親は、動作が後で変更されるオフセットを無視して、通常どおりに子をレイアウトします。問題はここにあります。この時点でのビューの値は、OnLayoutChangeListenerによってキャプチャされ、アニメーターに格納されます。アニメーションが実行されると、動作が定義する場所ではなく、これらの値にアニメーション化されます。残念ながら、LayoutTransitionクラスでは、アニメーターにアクセスして終了値を更新することはできません。
修正:現在、LayoutTransitionsを含むエレガントな修正は見当たりません。 LayoutTransitionアニメーターにアクセスして更新する方法のバグを送信します。今のところ、layoutTransition.setAnimateParentHierachy(false)
を使用して親コンテナのlayoutTransitionを無効にすることができます。次に、変更を自分でアニメーション化できます。できるだけ早く、実際の例で答えを更新します。
質問は2年以上前に行われましたが、残念ながら問題は解決していません。
animateLayoutChanges="true"
を使用しながら、BottomSheetでaddView
関数とremoveView
関数の呼び出しを維持するソリューションをついに手に入れました。
BottomSheetBehavior
は、変更時に正しい高さを計算できないため、高さは同じままである必要があります。これを行うには、BottomSheet
の高さをmatch_parent
に設定し、コンテンツと、コンテンツの高さに応じて高さを変更するSpace
の2つの子に分割します。
BottomSheet
の実際の動作を最もよく模倣するには、BottomSheet
が拡張されたときに背景を暗くするだけでなく、BottomSheet
を閉じたときに背景を暗くするTouchToDismissビューを追加する必要もあります。ユーザーがコンテンツの外側を押します。
コードは次のとおりです。
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 )には、[〜#〜] top [〜#〜]の重力があります。ダイアログのdesign_bottom_sheet
FrameLayout:
Android:layout_gravity="center_horizontal|top"
BottomSheetDialogの重力が一番上にある理由はよくわかりません。
プロジェクトに同じレイアウトファイル(同じコンテンツと名前)を作成し、この行を次のように置き換える必要があります。
Android:layout_gravity="center_horizontal|bottom"