435 lines
11 KiB
Python
435 lines
11 KiB
Python
"""
|
|
Components/SliverAppbar
|
|
=======================
|
|
|
|
.. versionadded:: 1.0.0
|
|
|
|
.. rubric:: MDSliverAppbar is a Material Design widget in KivyMD which gives
|
|
scrollable or collapsible
|
|
`MDTopAppBar <https://kivymd.readthedocs.io/en/latest/components/appbar/>`_
|
|
|
|
.. 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 <https://github.com/kivymd-extensions/akivymd/blob/main/kivymd_extensions/akivymd/uix/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 = '''
|
|
<GuitarItem>
|
|
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
|