Mam niestandardowy BttomSheetDialogFragment i chcę mieć zaokrąglone rogi w górnej części widoku od dołu
to jest moja niestandardowa klasa, która zawyża mój układ, który chcę wyświetlać od dołu
View mView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.charge_layout, container, false);
initChargeLayoutViews();
return mView;
}
a także mam ten plik zasobów xml jako tło:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners android:topRightRadius="35dp"
android:topLeftRadius="35dp"
/>
<solid android:color="@color/white"/>
<padding android:top="10dp"
android:bottom="10dp"
android:right="16dp"
android:left="16dp"/>
ale problem polega na tym, że kiedy ustawię ten plik zasobów jako tło elementu głównego mojego układu, rogi nadal nie są zaokrąglone
i nie mogę użyć poniższego kodu:
this.getDialog().getWindow().setBackgroundDrawableResource(R.drawable.charge_layout_background);
ponieważ zastępuje domyślne tło BottomSheetDialog i nie będzie żadnego półprzezroczystego szarego koloru nad moim widokiem z dołu
android
material-design
bottom-sheet
material-components-android
material-components
Rasool Ghana
źródło
źródło
Odpowiedzi:
Utwórz niestandardowy element do rysowania
rounded_dialog.xml
:<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/white"/> <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"/> </shape>
Następnie nadpisać
bottomSheetDialogTheme
nastyles.xml
korzystania z rozciągliwej jako tło:<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item> </style> <style name="AppBottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog"> <item name="bottomSheetStyle">@style/AppModalStyle</item> </style> <style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal"> <item name="android:background">@drawable/rounded_dialog</item> </style>
Spowoduje to zmianę wszystkich BottomSheetDialogs Twojej aplikacji.
źródło
rounded_dialog
&AppModalStyle
names z tłem, w którym tylko górne rogi są zaokrąglone, ponieważ spodziewałbyś się użyć takiego tła tylko ze stylem dolnego arkusza. Co powiesz nabottomsheet_rounded_background
&AppBottomSheetStyle
Dzięki nowej bibliotece komponentów materiałowych możesz dostosować kształt komponentu za pomocą
shapeAppearanceOverlay
atrybutu w swoim stylu ( uwaga: wymaga wersji 1.1.0 )Po prostu użyj
BottomSheetDialogFragment
nadpisywaniaonCreateView
metody, a następnie zdefiniuj własny styl dla okien dialogowych dolnego arkusza.Zdefiniuj
bottomSheetDialogTheme
atrybut wstyles.xml
motywie aplikacji:<!-- Base application theme. --> <style name="AppTheme" parent="Theme.MaterialComponents.Light"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> .... <item name="bottomSheetDialogTheme">@style/CustomBottomSheetDialog</item> </style>
Następnie po prostu zdefiniuj swój ulubiony kształt za pomocą
shapeAppearanceOverlay
<style name="CustomBottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDialog"> <item name="bottomSheetStyle">@style/CustomBottomSheet</item> </style> <style name="CustomBottomSheet" parent="Widget.MaterialComponents.BottomSheet"> <item name="shapeAppearanceOverlay">@style/CustomShapeAppearanceBottomSheetDialog</item> </style> <style name="CustomShapeAppearanceBottomSheetDialog" parent=""> <item name="cornerFamily">rounded</item> <item name="cornerSizeTopRight">16dp</item> <item name="cornerSizeTopLeft">16dp</item> <item name="cornerSizeBottomRight">0dp</item> <item name="cornerSizeBottomLeft">0dp</item> </style>
Możesz uzyskać to samo zachowanie, zastępując tę metodę w swoim
BottomSheetDialogFragment
(zamiast dodawaćbottomSheetDialogTheme
w motywie aplikacji):@Override public int getTheme() { return R.style.CustomBottomSheetDialog; }
W tym przypadku używasz tego motywu Nakładaj tylko w pojedynczej aplikacji,
BottomSheetDialogFragment
a nie w całej aplikacji.Ważna uwaga na temat STANU ROZSZERZONEGO :
W stanie rozwiniętym BottomSheet ma płaskie rogi . Możesz sprawdzić oficjalny komentarz w repozytorium github :
To zachowanie jest zapewniane przez
BottomSheetBehavior
i nie można go zastąpić.Istnieje jednak obejście -> ZRZECZENIE SIĘ: może przestać działać w następnych wersjach !!
Możesz dodać
BottomSheetCallback
wBottomSheetDialogFragment
:@NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); ((BottomSheetDialog)dialog).getBehavior().addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_EXPANDED) { //In the EXPANDED STATE apply a new MaterialShapeDrawable with rounded cornes MaterialShapeDrawable newMaterialShapeDrawable = createMaterialShapeDrawable(bottomSheet); ViewCompat.setBackground(bottomSheet, newMaterialShapeDrawable); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } }); return dialog; } @NotNull private MaterialShapeDrawable createMaterialShapeDrawable(@NonNull View bottomSheet) { ShapeAppearanceModel shapeAppearanceModel = //Create a ShapeAppearanceModel with the same shapeAppearanceOverlay used in the style ShapeAppearanceModel.builder(getContext(), 0, R.style.CustomShapeAppearanceBottomSheetDialog) .build(); //Create a new MaterialShapeDrawable (you can't use the original MaterialShapeDrawable in the BottoSheet) MaterialShapeDrawable currentMaterialShapeDrawable = (MaterialShapeDrawable) bottomSheet.getBackground(); MaterialShapeDrawable newMaterialShapeDrawable = new MaterialShapeDrawable((shapeAppearanceModel)); //Copy the attributes in the new MaterialShapeDrawable newMaterialShapeDrawable.initializeElevationOverlay(getContext()); newMaterialShapeDrawable.setFillColor(currentMaterialShapeDrawable.getFillColor()); newMaterialShapeDrawable.setTintList(currentMaterialShapeDrawable.getTintList()); newMaterialShapeDrawable.setElevation(currentMaterialShapeDrawable.getElevation()); newMaterialShapeDrawable.setStrokeWidth(currentMaterialShapeDrawable.getStrokeWidth()); newMaterialShapeDrawable.setStrokeColor(currentMaterialShapeDrawable.getStrokeColor()); return newMaterialShapeDrawable; }
źródło
Could not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior
BottomSheetDialog
Jest ustawienie domyślne Kolor biały, to dlaczego rogi nie są widoczne, w celu pokazania ich trzeba dokonać tle dialogowe przejrzysty nadrzędnymi styluBottomSheetDialog
.Zdefiniuj ten styl w swoim
res/values/styles/styles.xml
<style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog"> <item name="bottomSheetStyle">@style/bottomSheetStyleWrapper</item> </style> <style name="bottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal"> <item name="android:background">@android:color/transparent</item> </style>
I ustaw ten styl w oknie dialogowym BottomSheetDialog
View view = getLayoutInflater().inflate(R.layout.chooser_bottom_sheet, null); BottomSheetDialog dialog = new BottomSheetDialog(this,R.style.BottomSheetDialog); // Style here dialog.setContentView(view); dialog.show();
źródło
utwórz kształt o nazwie rounded_corners_shape
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:topLeftRadius="8dp" android:topRightRadius="8dp"/> <solid android:color="@color/white"/> </shape>
zdefiniować styl
<style name="AppBottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog"> <item name="bottomSheetStyle">@style/AppModalStyle</item> </style> <style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal"> <item name="android:background">@drawable/rounded_corners_shape</item> </style>
użyj tego stylu na swoim niestandardowym BottomSheetDialogFragment w ten sposób, będzie działać!
public class CustomDialogFragment extends BottomSheetDialogFragment { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setStyle(STYLE_NORMAL, R.style. AppBottomSheetDialogTheme); } ... }
źródło
Fragment
s.Jeśli używasz ostatniej wersji komponentu materiałowego , wystarczy nadpisać
ShapeAppearance.MaterialComponents.LargeComponent
(ponieważ dolny arkusz używa tego kształtu) i ustawić żądaną wartość, taką jak:<style name="ShapeAppearance.YourApp.LargeComponent" parent="ShapeAppearance.MaterialComponents.LargeComponent"> <item name="cornerFamily">rounded</item> <item name="cornerSize">12dp</item> </style>
A następnie ustaw w stylu swojej aplikacji:
<item name="shapeAppearanceLargeComponent">@style/ShapeAppearance.YourApp.LargeComponent</item>
Rozwiązanie Gabriele Mariotti jest podobne i też działa, ale to jest prostsze.
źródło
BottomSheetDialog
?ShapeAppearance.MaterialComponents.LargeComponent
będą miały ten sam rozmiar narożnika i rodzinę, a nie tylko arkusz dolny. Sprawdź wymagania dotyczące stylu i zdecyduj, czy chcesz zmienić wygląd wszystkich komponentów, czy tylko pojedynczych komponentów lub widżetów.Odpowiedź Koma Yip z innego pytania zadziałała dla mnie, powinieneś spróbować.
umieść to w węźle głównym XML układu:
a w
onCreateView()
skrócie:źródło
Sprawdzałem dzisiaj to samo i tak, miałeś rację co do śledzenia kodu
this.getDialog().getWindow().setBackgroundDrawableResource(R.drawable.charge_layout_background);
dotyczy to tła fragmentu, więc zamiast tego powinieneś pobrać widok dolnego arkusza z okna dialogowego i zmienić tło tutaj jest kod
@SuppressLint("RestrictedApi") @Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); View rootView = getActivity().getLayoutInflater().inflate(R.layout.view_member_info,null,false); unbinder = ButterKnife.bind(this, rootView); adjustUIComponents(); dialog.setContentView(rootView); FrameLayout bottomSheet = (FrameLayout) dialog.getWindow().findViewById(android.support.design.R.id.design_bottom_sheet); bottomSheet.setBackgroundResource(R.drawable.container_background); }
tutaj arkusz dolny to rzeczywisty widok, który chcesz zmienić.
źródło
BottomSheetDialogFragment
więc logiki wonCreateDialog
metodzieUtwórz kształt, który można narysować ..., który użyjemy jako tła dla dolnego arkusza. Podaj odpowiednią wartość promienia górnego lewego i prawego rogu.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:topLeftRadius="24dp" android:topRightRadius="24dp" /> <padding android:top="2dp" /> <solid android:color="@color/white" /> </shape>
Teraz utwórz styl dla „Fragment okna dialogowego dolnego arkusza”
<style name="BottomSheet" parent="@style/Widget.Design.BottomSheet.Modal"> <item name="android:background">@drawable/drawable_bottomsheet_background</item> </style> <style name="BaseBottomSheetDialog" parent="@style/Theme.Design.Light.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <item name="bottomSheetStyle">@style/BottomSheet</item> </style> <style name="BottomSheetDialogTheme" parent="BaseBottomSheetDialog" />
Teraz utwórz niestandardową klasę, która rozszerzy BottomSheetDilogFragment, w którym określisz swój styl.
open class CustomRoundBottomSheet : BottomSheetDialogFragment() { override fun getTheme(): Int = R.style.BottomSheetDialogTheme override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = BottomSheetDialog(requireContext(), theme) }
Teraz użyj tej klasy wszędzie tam, gdzie chcesz mieć zaokrąglony dolny arkusz. na przykład
class BottomSheetSuccess : CustomRoundBottomSheet() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.bottomsheet_shopcreate_success, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) } }
źródło
U mnie to zadziałało
utwórz kształt o nazwie shape_rounded_dialog
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/color_white" /> <corners android:topLeftRadius="16dp" android:topRightRadius="16dp" />
dodaj poniższe style
<style name="AppBottomSheetDialogTheme" parent="Theme.MaterialComponents.Light.BottomSheetDialog"> <item name="bottomSheetStyle">@style/CustomBottomSheetStyle</item> </style> <style name="CustomBottomSheetStyle" parent="Widget.Design.BottomSheet.Modal"> <item name="android:background">@drawable/shape_rounded_dialog</item> </style>
W klasie DialogFragment przesłanianie metody getTheme również zwraca styl Yourself.
@Override public int getTheme() { return R.style.AppBottomSheetDialogTheme; }
źródło
Ta odpowiedź dotyczy tylko kwestii ustawienia koloru tła
Color.TRANSPARENT
po ustawieniu rysowalnego z zaokrąglonym tłem do układu.Żadna z odpowiedzi nie działała dla mnie, aby ustawić kolor tła, z
Color.TRANSPARENT
wyjątkiemsetupDialog()
rozwiązania zastępującego :@Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); View contentView = View.inflate(getContext(), R.layout.fragment_bottom_sheet, null); dialog.setContentView(contentView); ... ((View) contentView.getParent()).setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent)); }
ALE
contentView
ustawić na oknie o to nieview
można dostać wonViewCreated()
przypadku pompowania wonCreateView()
. Łamie standardowy przepływ, więc może wydać problemy jak nie można korzystaćView Bindings
-Kotlin Android Extensions
wonViewCreated()
Więc trochę poprawiam, żeby ustawić tło w
onActivityCreated()
:override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) (view?.parent as View).setBackgroundColor(Color.TRANSPARENT) }
Mam nadzieję, że ta pomoc, która ma te same problemy
źródło
Wiem, że to pytanie ma już zaakceptowaną odpowiedź. Chciałbym udokumentować problemy, przez które przeszedłem i jak to w końcu działało, aby było to przydatne dla kogoś w przyszłości.
Po pierwsze,
Theme.AppCompat.Light.DarkActionBar
jako rodzic dla naszegoAppTheme
. Oznaczało to, że rozwiązanie @Gabriele Mariotti ciągle ulegało awarii z błędemCould not inflate Behavior subclass com.google.android.material.bottomsheet.BottomSheetBehavior
. Naprawiłem to, po prostu zmieniając rodzica naTheme.MaterialComponents.Light.DarkActionBar
. Nie wpłynęło to w żaden sposób na nasz motyw, ale RTE zniknęło. Możesz również rozwiązać ten problem, po prostu dołączając wymagane elementy do swojego stylu. Ale nie zawracałem sobie głowy ustalaniem, które style były wymagane przez BottomSheetBehavior.Po drugie, spróbuj, jak mogłem, ale nie mogłem uzyskać rzeczywistego układu ramki (którym był BottomSheetDialogFragment), którego używa, aby mieć zaokrąglone rogi. Zdałem sobie sprawę, że ustawienie tego na obraz do rysowania działało, ale nie w przypadku kształtu lub
@null
. Okazało się, że to dlatego,LinearLayout
że używany przeze mnie miał zdefiniowane tło. To przesłaniało wszelkie tło w stylu. Usunięcie tego ostatecznie zaowocowało zaokrąglonymi narożnikami.Nie wymagałem też, aby kształt tła był zaokrąglany w rogach. Rozwiązanie @Gabriele Mariotti działało, gdy tylko wprowadziłem powyższe zmiany. Jednak aby ustawić kolor tła na taki, jaki chciałem, musiałem nadpisać element „backgroundTint”.
PS: Jestem nowy w programowaniu Android i utrzymuję starą aplikację, która została stworzona do użytku wewnętrznego w naszej uczelni. Nie jestem zbyt zaznajomiony z układem Androida ani z biblioteką materiałów. Myślę, że dlatego zajęło mi to 3 dni. Mam nadzieję, że przyda się to komuś w przyszłości.
źródło
Dodaj te dwie metody do swojej klasy BottomsheetDialogFragment.
public void setDialogBorder(Dialog dialog) { FrameLayout bottomSheet = (FrameLayout) dialog.getWindow().findViewById(android.support.design.R.id.design_bottom_sheet); bottomSheet.setBackground(new ColorDrawable(Color.TRANSPARENT)); setMargins(bottomSheet, 10, 0, 10, 20); } private void setMargins(View view, int left, int top, int right, int bottom) { if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); p.setMargins(left, top, right, bottom); view.requestLayout(); } }
Teraz wywołaj
setDialogBorder(dialog)
metodę wsetupDialog()
metodzie klasy BottomsheetDialogFragment.Teraz utwórz plik kształtu w folderze do rysowania.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="20dp" /> <solid android:color="@color/white" /> <stroke android:width="1dp" android:color="@color/transparent" /> </shape>
Teraz ustaw tło dla widoku okna dialogowego nadrzędnej grupy widoków w pliku xml.
android:background="@drawable/round_border_white"
Gotowe!!
źródło
dodaj kształt z zaokrąglonym rogiem, ustaw go jako tło dla układu głównego
<?xml version="1.0" encoding="utf-8" ?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:topLeftRadius="@dimen/padding_margin_16_dp" android:topRightRadius="@dimen/padding_margin_16_dp" /> <solid android:color="@color/white" /> </shape>
ustaw przezroczystość tła w Twoim BottomSheetDialogFragment
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) (view?.parent as View).setBackgroundColor(Color.TRANSPARENT) }
jego praca dla Contraintlayout, Framelyaout, Linearlayout, Relativelayout.
źródło
Innym sposobem rozwiązania tego problemu jest rozszerzenie BottomSheetDialog i utworzenie niestandardowej klasy, która odpowiada Twoim potrzebom. Możesz zrobić to samo dla pliku xml układu i dodać tło lub inne potrzebne dostosowania. Ma to również tę zaletę, że nie będziesz zależny od nazw identyfikatorów używanych przez Androida (android.support.design.R.id.design_bottom_sheet) podczas zmiany tła (choć zmiana nazwy identyfikatora rzadko się zdarza AFAIK).
źródło
Utwórz niestandardowy element do rysowania z zaokrąglonym rogiem i ustaw go jako tło katalogu głównego układu BottomSheetDialogFragment
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/colorPrimary" /> <corners android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp" android:topLeftRadius="12dp" android:topRightRadius="12dp" /> </shape>
A następnie po prostu dodaj poniższy kod do swojej klasy BottomSheetDialogFragment
@Override public void setupDialog(Dialog dialog, int style) { super.setupDialog(dialog, style); View contentView = View.inflate(getContext(), R.layout.fragment_bottom_sheet, null); dialog.setContentView(contentView); CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()) .getLayoutParams(); CoordinatorLayout.Behavior behavior = params.getBehavior(); ((View) contentView.getParent()).setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent)); }
Możesz nawet grać z parametrami, aby ustawić margines, jak poniżej
params.setMargins(50, 0, 50, 0);
źródło
Musisz zmienić
bottom sheet theme
aby uzyskać górny układ rundyUtwórz niestandardowy do rysowania background_bottom_sheet_dialog_fragment.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:topLeftRadius="8dp" android:topRightRadius="8dp" /> <padding android:top="0dp" /> <solid android:color="@color/white" /> </shape>
Następnie nadpisz bottomSheetDialogTheme na styles.xml, używając jako tła do rysowania:
<!--Bottom sheet--> <style name="BottomSheet" parent="@style/Widget.Design.BottomSheet.Modal"> <item name="android:background">@drawable/background_bottom_sheet_dialog_fragment </item> </style> <style name="BaseBottomSheetDialog" parent="@style/Theme.Design.Light.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <item name="bottomSheetStyle">@style/BottomSheet</item> </style> <style name="BottomSheetDialogTheme" parent="BaseBottomSheetDialog" />
Spowoduje to zmianę układu tła dolnego arkusza
BottomSheetDialog
class SheetFragment() : BottomSheetDialogFragment() { lateinit var binding: SheetFragmentBinding; override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog; val view = View.inflate(context, R.layout.fragment_bottom_sheet, null); binding = DataBindingUtil.bind(view)!!; binding.viewModel = SheetFragmentVM(); dialog.setContentView(view); var bottomSheetBehavior = BottomSheetBehavior.from(view.parent as View); bottomSheetBehavior.setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO); bottomSheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { if (BottomSheetBehavior.STATE_EXPANDED == newState) { // do on STATE_EXPANDED } if (BottomSheetBehavior.STATE_COLLAPSED == newState) { // do on STATE_COLLAPSED } if (BottomSheetBehavior.STATE_HIDDEN == newState) { dismiss() } } override fun onSlide(bottomSheet: View, slideOffset: Float) { // do on slide } }) return dialog }
źródło