BottomSheet#
#
See also
Bottom sheets are surfaces containing supplementary content that are anchored to the bottom of the screen.
Usage#
Root:
MDNavigationLayout:
MDScreenManager:
[...]
MDBottomSheet:
The bottom sheet has two types:
Standard#
Standard bottom sheets co-exist with the screen’s main UI region and allow for simultaneously viewing and interacting with both regions, especially when the main UI region is frequently scrolled or panned.
Use a standard bottom sheet to display content that complements the screen’s primary content, such as an audio player in a music app.
Standard bottom sheets are elevated above the main UI region so their visibility is not affected by panning or scrolling.
Modal#
Like dialogs, modal bottom sheets appear in front of app content, disabling all other app functionality when they appear, and remaining on screen until confirmed, dismissed, or a required action has been taken.
Tapping the scrim dismisses a modal bottom sheet.
Add elements to MDBottomSheetDragHandleTitle class#
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
MDBottomSheet:
size_hint_y: None
height: "84dp"
MDBottomSheetDragHandle:
MDBottomSheetDragHandleTitle:
text: "MDBottomSheet"
adaptive_height: True
pos_hint: {"center_y": .5}
MDBottomSheetDragHandleButton:
icon: "close"
'''
class Example(MDApp):
def build(self):
return Builder.load_string(KV)
Example().run()
from kivymd.app import MDApp
from kivymd.uix.bottomsheet import (
MDBottomSheet,
MDBottomSheetDragHandle,
MDBottomSheetDragHandleTitle,
MDBottomSheetDragHandleButton,
)
from kivymd.uix.screen import MDScreen
class Example(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
return (
MDScreen(
MDBottomSheet(
MDBottomSheetDragHandle(
MDBottomSheetDragHandleTitle(
text="MDBottomSheet",
adaptive_height=True,
pos_hint={"center_y": 0.5},
),
MDBottomSheetDragHandleButton(
icon="close",
),
),
size_hint_y=None,
height="84dp",
),
md_bg_color=self.theme_cls.backgroundColor,
)
)
Example().run()
A practical example with standard bottom sheet#
(A double tap on the map to open the bottom sheet)
import asynckivy
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty
from kivy_garden.mapview import MapView
from kivymd.app import MDApp
from kivymd.uix.behaviors import TouchBehavior
from kivymd.uix.boxlayout import MDBoxLayout
KV = '''
#:import MapSource kivy_garden.mapview.MapSource
#:import asynckivy asynckivy
<TypeMapElement>
orientation: "vertical"
adaptive_height: True
spacing: "8dp"
MDIconButton:
id: icon
icon: root.icon
theme_bg_color: "Custom"
md_bg_color: "#EDF1F9" if not root.selected else app.theme_cls.primaryColor
pos_hint: {"center_x": .5}
theme_icon_color: "Custom"
icon_color: "white" if root.selected else "black"
on_release: app.set_active_element(root, root.title.lower())
MDLabel:
text: root.title
pos_hint: {"center_x": .5}
halign: "center"
adaptive_height: True
MDScreen:
MDNavigationLayout:
MDScreenManager:
MDScreen:
CustomMapView:
bottom_sheet: bottom_sheet
map_source: MapSource(url=app.map_sources[app.current_map])
lat: 46.5124
lon: 47.9812
zoom: 12
MDBottomSheet:
id: bottom_sheet
sheet_type: "standard"
size_hint_y: None
height: "150dp"
on_open: asynckivy.start(app.generate_content())
MDBottomSheetDragHandle:
drag_handle_color: "grey"
MDBottomSheetDragHandleTitle:
text: "Select type map"
pos_hint: {"center_y": .5}
MDBottomSheetDragHandleButton:
icon: "close"
ripple_effect: False
on_release: bottom_sheet.set_state("toggle")
BoxLayout:
id: content_container
padding: 0, 0, 0, "16dp"
'''
class TypeMapElement(MDBoxLayout):
selected = BooleanProperty(False)
icon = StringProperty()
title = StringProperty()
class CustomMapView(MapView, TouchBehavior):
bottom_sheet = ObjectProperty()
def on_double_tap(self, touch, *args):
if self.bottom_sheet:
self.bottom_sheet.set_state("toggle")
class Example(MDApp):
map_sources = {
"street": "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}",
"sputnik": "https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"hybrid": "https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
}
current_map = StringProperty("street")
async def generate_content(self):
icons = {
"street": "google-street-view",
"sputnik": "space-station",
"hybrid": "map-legend",
}
if not self.root.ids.content_container.children:
for i, title in enumerate(self.map_sources.keys()):
await asynckivy.sleep(0)
self.root.ids.content_container.add_widget(
TypeMapElement(
title=title.capitalize(),
icon=icons[title],
selected=not i,
)
)
def set_active_element(self, instance, type_map):
for element in self.root.ids.content_container.children:
if instance == element:
element.selected = True
self.current_map = type_map
else:
element.selected = False
def build(self):
return Builder.load_string(KV)
Example().run()
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty
from kivy_garden.mapview import MapView
import asynckivy
from kivy_garden.mapview import MapSource
from kivymd.app import MDApp
from kivymd.uix.behaviors import TouchBehavior, DeclarativeBehavior
from kivymd.uix.bottomsheet import (
MDBottomSheet,
MDBottomSheetDragHandle,
MDBottomSheetDragHandleTitle,
MDBottomSheetDragHandleButton,
)
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDIconButton
from kivymd.uix.label import MDLabel
from kivymd.uix.navigationdrawer import MDNavigationLayout
from kivymd.uix.screen import MDScreen
from kivymd.uix.screenmanager import MDScreenManager
class TypeMapElement(MDBoxLayout):
selected = BooleanProperty(False)
icon = StringProperty()
title = StringProperty()
class CustomMapView(DeclarativeBehavior, MapView, TouchBehavior):
bottom_sheet = ObjectProperty()
def on_double_tap(self, touch, *args):
if self.bottom_sheet:
self.bottom_sheet.set_state("toggle")
class Example(MDApp):
map_sources = {
"street": "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}",
"sputnik": "https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"hybrid": "https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
}
current_map = StringProperty("street")
async def generate_content(self):
icons = {
"street": "google-street-view",
"sputnik": "space-station",
"hybrid": "map-legend",
}
if not self.screen.get_ids().content_container.children:
for i, title in enumerate(self.map_sources.keys()):
await asynckivy.sleep(0)
type_map_element = TypeMapElement(
MDIconButton(
id=f"icon_{icons[title]}",
icon=icons[title],
theme_bg_color="Custom",
md_bg_color="#EDF1F9",
pos_hint={"center_x": 0.5},
theme_icon_color="Custom",
icon_color="black"
),
MDLabel(
text=title,
pos_hint={"center_x": 0.5},
halign="center",
adaptive_height=True,
),
orientation="vertical",
adaptive_height=True,
spacing="8dp",
title=title.capitalize(),
icon=icons[title],
selected=not i,
)
icon = type_map_element.get_ids()[f"icon_{icons[title]}"]
icon.bind(
on_release=lambda x=icon, z=type_map_element, y=title.lower(): self.set_active_element(
x, z, y
)
)
self.screen.get_ids().content_container.add_widget(
type_map_element
)
def set_active_element(self, button, instance, type_map):
for element in self.screen.get_ids().content_container.children:
if instance is element:
element.selected = True
button.md_bg_color = self.theme_cls.primaryColor
button.icon_color = "white"
self.current_map = type_map
self.screen.get_ids().custom_mapview.map_source = MapSource(
url=self.map_sources[self.current_map]
)
else:
for widget in element.children:
if isinstance(widget, MDIconButton) and not widget is button:
element.selected = False
widget.md_bg_color = "#EDF1F9"
widget.icon_color = "black"
def build(self):
self.screen = MDScreen(
MDNavigationLayout(
MDScreenManager(
MDScreen(
CustomMapView(
id="custom_mapview",
map_source=MapSource(
url=self.map_sources[self.current_map]
),
lat=46.5124,
lon=47.9812,
zoom=12,
)
)
),
MDBottomSheet(
MDBottomSheetDragHandle(
MDBottomSheetDragHandleTitle(
text="Select type map",
pos_hint={"center_y": 0.5},
),
MDBottomSheetDragHandleButton(
id="handle_button",
icon="close",
ripple_effect=False,
),
drag_handle_color="grey",
),
MDBoxLayout(
id="content_container",
padding=(0, 0, 0, "16dp"),
),
id="bottom_sheet",
sheet_type="standard",
size_hint_y=None,
height="150dp",
on_open=lambda x: asynckivy.start(self.generate_content()),
),
)
)
bottom_sheet = self.screen.get_ids().bottom_sheet
self.screen.get_ids().custom_mapview.bottom_sheet = bottom_sheet
self.screen.get_ids().handle_button.bind(
on_release=lambda x: bottom_sheet.set_state("toggle")
)
return self.screen
Example().run()
API break#
1.2.0 version#
Root:
MDBottomSheet:
# Optional.
MDBottomSheetDragHandle:
# Optional.
MDBottomSheetDragHandleTitle:
# Optional.
MDBottomSheetDragHandleButton:
MDBottomSheetContent:
[...]
2.0.0 version#
Root:
MDNavigationLayout:
MDScreenManager:
# Your screen.
MDScreen:
MDBottomSheet:
# Optional.
MDBottomSheetDragHandle:
# Optional.
MDBottomSheetDragHandleTitle:
# Optional.
MDBottomSheetDragHandleButton:
icon: "close"
# Your content.
BoxLayout:
API - kivymd.uix.bottomsheet.bottomsheet#
- class kivymd.uix.bottomsheet.bottomsheet.MDBottomSheetDragHandleButton(**kwargs)#
Implements a close button (or other functionality) for the
MDBottomSheetDragHandlecontainer.For more information, see in the
MDIconButtonclass documentation.Added in version 1.2.0.
- class kivymd.uix.bottomsheet.bottomsheet.MDBottomSheetDragHandleTitle(*args, **kwargs)#
Implements a header for the
MDBottomSheetDragHandlecontainer.For more information, see in the
MDLabelclass documentation.Added in version 1.2.0.
- class kivymd.uix.bottomsheet.bottomsheet.MDBottomSheetDragHandle(*args, **kwargs)#
Implements a container that can place the header of the bottom sheet and the close button. Also implements the event of dragging the bottom sheet on the parent screen.
For more information, see in the
DeclarativeBehaviorandBoxLayoutclasses documentation.Added in version 1.2.0.
- drag_handle_color#
Color of drag handle element in (r, g, b, a) or string format.
MDBottomSheet: MDBottomSheetDragHandle: drag_handle_color: "white"
drag_handle_coloris anColorPropertyand defaults to None.
- add_widget(widget, *args, **kwargs)#
Add a new widget as a child of this widget.
- Parameters:
- widget:
Widget Widget to add to our list of children.
- index: int, defaults to 0
Index to insert the widget in the list. Notice that the default of 0 means the widget is inserted at the beginning of the list and will thus be drawn on top of other sibling widgets. For a full discussion of the index and widget hierarchy, please see the Widgets Programming Guide.
Added in version 1.0.5.
- canvas: str, defaults to None
Canvas to add widget’s canvas to. Can be ‘before’, ‘after’ or None for the default canvas.
Added in version 1.9.0.
- widget:
>>> from kivy.uix.button import Button >>> from kivy.uix.slider import Slider >>> root = Widget() >>> root.add_widget(Button()) >>> slider = Slider() >>> root.add_widget(slider)
- class kivymd.uix.bottomsheet.bottomsheet.MDBottomSheet(*args, **kwargs)#
Bottom sheet class.
For more information, see in the
MDNavigationDrawerclass documentation.- sheet_type#
Type of sheet.
Standard bottom sheets co-exist with the screen’s main UI region and allow for simultaneously viewing and interacting with both regions, especially when the main UI region is frequently scrolled or panned. Use a standard bottom sheet to display content that complements the screen’s primary content, such as an audio player in a music app.
Like dialogs, modal bottom sheets appear in front of app content, disabling all other app functionality when they appear, and remaining on screen until confirmed, dismissed, or a required action has been taken.
Changed in version 2.0.0: Rename from type to sheet_type.
sheet_typeis aOptionPropertyand defaults to ‘modal’.
- on_sheet_type(instance, value) None#
Fired when the
sheet_typevalue changes.
- add_widget(widget, *args, **kwargs)#
Add a new widget as a child of this widget.
- Parameters:
- widget:
Widget Widget to add to our list of children.
- index: int, defaults to 0
Index to insert the widget in the list. Notice that the default of 0 means the widget is inserted at the beginning of the list and will thus be drawn on top of other sibling widgets. For a full discussion of the index and widget hierarchy, please see the Widgets Programming Guide.
Added in version 1.0.5.
- canvas: str, defaults to None
Canvas to add widget’s canvas to. Can be ‘before’, ‘after’ or None for the default canvas.
Added in version 1.9.0.
- widget:
>>> from kivy.uix.button import Button >>> from kivy.uix.slider import Slider >>> root = Widget() >>> root.add_widget(Button()) >>> slider = Slider() >>> root.add_widget(slider)
- on_touch_move(touch)#
Receive a touch move event. The touch is in parent coordinates.
See
on_touch_down()for more information.