""" Components/SliverAppbar ======================= .. versionadded:: 1.0.0 .. rubric:: MDSliverAppbar is a Material Design widget in KivyMD which gives scrollable or collapsible `MDTopAppBar `_ .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-appbar-preview.gif :align: center .. note:: This widget is a modification of the `silverappbar.py `_ module. Usage ----- .. code-block:: kv MDScreen: MDSliverAppbar: MDTopAppBar: [...] MDSliverAppbarHeader: # Custom content. [...] # Custom list. MDSliverAppbarContent: Anatomy ------- .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-appbar-anatomy.png :align: center Example ------- .. code-block:: python from kivy.lang.builder import Builder from kivymd.app import MDApp from kivymd.uix.list import MDListItem KV = ''' theme_bg_color: "Custom" md_bg_color: "2d4a50" MDListItemLeadingAvatar source: "avatar.png" MDListItemHeadlineText: text: "Ibanez" MDListItemSupportingText: text: "GRG121DX-BKF" MDListItemTertiaryText: text: "$445,99" MDListItemTrailingIcon: icon: "guitar-electric" MDScreen: MDSliverAppbar: background_color: "2d4a50" hide_appbar: True MDTopAppBar: type: "medium" MDTopAppBarLeadingButtonContainer: MDActionTopAppBarButton: icon: "arrow-left" MDTopAppBarTitle: text: "Sliver toolbar" MDTopAppBarTrailingButtonContainer: MDActionTopAppBarButton: icon: "attachment" MDActionTopAppBarButton: icon: "calendar" MDActionTopAppBarButton: icon: "dots-vertical" MDSliverAppbarHeader: FitImage: source: "bg.jpg" MDSliverAppbarContent: id: content orientation: "vertical" padding: "12dp" theme_bg_color: "Custom" md_bg_color: "2d4a50" ''' class GuitarItem(MDListItem): ... class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" return Builder.load_string(KV) def on_start(self): for x in range(10): self.root.ids.content.add_widget(GuitarItem()) Example().run() API break ========= 1.2.0 version ------------- .. code-block:: kv #:import SliverToolbar __main__.SliverToolbar Root: MDSliverAppbar: [...] MDSliverAppbarHeader: [...] MDSliverAppbarContent: [...] .. code-block:: python class SliverToolbar(MDTopAppBar): [...] 2.0.0 version ------------- .. code-block:: kv Root: MDSliverAppbar: [...] MDTopAppBar: [...] MDSliverAppbarHeader: [...] MDSliverAppbarContent: [...] """ __all__ = ("MDSliverAppbar", "MDSliverAppbarHeader", "MDSliverAppbarContent") import os from kivy.clock import Clock from kivy.core.window import Window from kivy.lang.builder import Builder from kivy.properties import ( BooleanProperty, ColorProperty, NumericProperty, VariableListProperty, ObjectProperty, ) from kivy.uix.boxlayout import BoxLayout from kivymd import uix_path from kivymd.theming import ThemableBehavior from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.appbar import MDTopAppBar with open( os.path.join(uix_path, "sliverappbar", "sliverappbar.kv"), encoding="utf-8" ) as kv_file: Builder.load_string(kv_file.read()) class MDSliverAppbarException(Exception): pass class MDSliverAppbarContent(MDBoxLayout): """ Implements a box for a scrollable list of custom items. For more information, see in the :class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation. """ class MDSliverAppbarHeader(BoxLayout): """ Sliver app bar header class. For more information, see in the :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. """ class MDSliverAppbar(ThemableBehavior, BoxLayout): """ Sliver appbar class. For more information, see in the :class:`~kivymd.theming.ThemableBehavior` and :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation. :Events: :attr:`on_scroll_content` Fired when the list of custom content is being scrolled. """ background_color = ColorProperty(None) """ Background color of appbar in (r, g, b, a) or string format. :attr:`background_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ max_height = NumericProperty(Window.height / 2) """ Distance from top of screen to start of custom list content. .. code-block:: kv MDSliverAppbar: max_height: "200dp" .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-appbar-max-height.png :align: center :attr:`max_height` is an :class:`~kivy.properties.NumericProperty` and defaults to `Window.height / 2`. """ hide_appbar = BooleanProperty(None) """ Whether to hide the appbar when scrolling through a list of custom content. .. versionchanged:: 2.0.0 Rename `hide_toolbar` to `hide_appbar` attribute. .. code-block:: kv MDSliverAppbar: hide_appbar: False .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-appbar-hide-appbar-false.gif :align: center .. code-block:: kv MDSliverAppbar: hide_appbar: True .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-appbar-hide-appbar-true.gif :align: center :attr:`hide_appbar` is an :class:`~kivy.properties.BooleanProperty` and defaults to `None`. """ radius = VariableListProperty([20], length=4) """ Box radius for custom item list. .. code-block:: kv MDSliverAppbar: radius: 20 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-app-bar-radius.png :align: center :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` and defaults to `[20]`. """ max_opacity = NumericProperty(1) """ Maximum background transparency value for the :class:`~kivymd.uix.sliverappbar.sliverappbar.MDSliverAppbarHeader` class. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-app-bar-max-opacity.gif :align: center .. code-block:: kv MDSliverAppbar: max_opacity: .5 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliver-app-bar-max-opacity-05.gif :align: center :attr:`max_opacity` is an :class:`~kivy.properties.NumericProperty` and defaults to `1`. """ _opacity = NumericProperty() _scroll_was_moving = BooleanProperty(False) _last_scroll_y_pos = 0.0 _appbar = ObjectProperty() def __init__(self, **kwargs): super().__init__(**kwargs) self.register_event_type("on_scroll_content") def on_hide_appbar(self, instance, value) -> None: """Fired when the `hide_appbar` value changes.""" if not value: self.background_color = self.theme_cls.transparentColor def on_scroll_content( self, instance: object = None, value: float = 1.0, direction: str = "up", ): """ Fired when the list of custom content is being scrolled. :param instance: :class:`~MDSliverAppbar` :param value: see :attr:`~kivy.uix.scrollview.ScrollView.scroll_y` :param direction: scroll direction: 'up/down' """ def on_background_color(self, instance, color) -> None: """Fired when the `background_color` value changes.""" if self._appbar: self._appbar.canvas.get_group("md-top-app-bar-color")[ 0 ].rgba = color def on_vbar(self) -> None: if not self.background_color: self.background_color = self.theme_cls.primaryColor scroll_box = self.ids.scroll_box vbar = self.ids.scroll.vbar appbar_percent = (self._appbar.height / scroll_box.height) * 100 current_percent = (vbar[0] + vbar[1]) * 100 percent_min = ( 1 - self.max_height / scroll_box.height ) * 100 + appbar_percent if self._scroll_was_moving: direction = self._get_direction_swipe(self.ids.scroll.scroll_y) self._last_scroll_y_pos = self.ids.scroll.scroll_y self.dispatch( "on_scroll_content", self.ids.scroll.scroll_y, direction ) if self.hide_appbar: if percent_min <= current_percent: opacity = (current_percent - percent_min) / (100 - percent_min) self._opacity = self.max_opacity * (1 - opacity) self.background_color = self.background_color[0:3] + [ 1 - opacity ] else: self.background_color = self.background_color[0:3] + [1] def add_widget(self, widget, index=0, canvas=None): if isinstance(widget, MDSliverAppbarContent): Clock.schedule_once(lambda x: self._set_radius(widget)) self.ids.scroll_box.add_widget(widget) elif isinstance(widget, MDSliverAppbarHeader): self.ids.header.add_widget(widget) elif isinstance(widget, MDTopAppBar): self._appbar = widget widget.pos_hint = {"top": 1} self.ids.float_box.add_widget(widget) else: super().add_widget(widget, index=index, canvas=canvas) def on__appbar(self, instance, value): def set_rgba_appbar(*args): if self.hide_appbar: value.theme_elevation_level = "Custom" value.elevation_level = 0 value.theme_shadow_color = "Custom" value.shadow_color = self.theme_cls.transparentColor value.md_bg_color = self.theme_cls.transparentColor value.canvas.get_group("md-top-app-bar-color")[ 0 ].rgba = self.theme_cls.transparentColor Clock.schedule_once(set_rgba_appbar, 0.5) def _set_radius(self, instance: MDSliverAppbarContent): instance.radius = self.radius def _get_direction_swipe(self, current_percent: float): if self._last_scroll_y_pos > current_percent: direction = "up" else: direction = "down" return direction