test-kivy-app/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.py

530 lines
14 KiB
Python
Raw Permalink Normal View History

2024-09-15 12:12:16 +00:00
"""
Components/ExpansionPanel
=========================
.. rubric:: Expansion panels contain creation flows and allow lightweight editing of an element.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel.png
:align: center
Usage
-----
.. code-block:: python
2024-09-15 17:57:02 +00:00
MDExpansionPanel:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDExpansionPanelHeader:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
# Content of header.
[...]
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDExpansionPanelContent:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
# Content of panel.
[...]
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Anatomy
-------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel-anatomy.png
:align: center
2024-09-15 12:12:16 +00:00
Example
-------
.. code-block:: python
from kivy.lang import Builder
2024-09-15 17:57:02 +00:00
from kivy.uix.behaviors import ButtonBehavior
2024-09-15 12:12:16 +00:00
from kivymd.app import MDApp
2024-09-15 17:57:02 +00:00
from kivymd.uix.behaviors import RotateBehavior
from kivymd.uix.expansionpanel import MDExpansionPanel
from kivymd.uix.list import MDListItemTrailingIcon
2024-09-15 12:12:16 +00:00
KV = '''
2024-09-15 17:57:02 +00:00
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
MDExpansionPanel:
id: panel
pos_hint: {"center_x": .5, "center_y": .5}
MDExpansionPanelHeader:
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowColor
ripple_effect: False
MDListItemSupportingText:
text: "Supporting text"
TrailingPressedIconButton:
id: chevron
icon: "chevron-right"
on_release: app.tap_expansion_chevron(panel, chevron)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDExpansionPanelContent:
orientation: "vertical"
padding: "12dp", 0, "12dp", 0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDLabel:
text: "Channel information"
adaptive_height: True
padding_x: "16dp"
padding_y: "12dp"
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDListItem:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDListItemLeadingIcon:
icon: "email"
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDListItemHeadlineText:
text: "Email"
MDListItemSupportingText:
text: "kivydevelopment@gmail.com"
MDListItem:
MDListItemLeadingIcon:
icon: "instagram"
MDListItemHeadlineText:
text: "Instagram"
MDListItemSupportingText:
text: "Account"
MDListItemTertiaryText:
text: "www.instagram.com/KivyMD"
2024-09-15 12:12:16 +00:00
'''
2024-09-15 17:57:02 +00:00
class TrailingPressedIconButton(
ButtonBehavior, RotateBehavior, MDListItemTrailingIcon
):
...
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class Example(MDApp):
2024-09-15 12:12:16 +00:00
def build(self):
2024-09-15 17:57:02 +00:00
self.theme_cls.theme_style = "Dark"
2024-09-15 12:12:16 +00:00
return Builder.load_string(KV)
2024-09-15 17:57:02 +00:00
def tap_expansion_chevron(
self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton
):
panel.open() if not panel.is_open else panel.close()
panel.set_chevron_down(
chevron
) if not panel.is_open else panel.set_chevron_up(chevron)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel-example.gif
:align: center
Use with ScrollView
-------------------
.. code-block:: python
import asynckivy
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.uix.behaviors import ButtonBehavior
from kivymd.app import MDApp
from kivymd.uix.behaviors import RotateBehavior
from kivymd.uix.expansionpanel import MDExpansionPanel
from kivymd.uix.list import MDListItemTrailingIcon
KV = '''
<ExpansionPanelItem>
MDExpansionPanelHeader:
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowColor
ripple_effect: False
MDListItemSupportingText:
text: "Supporting text"
TrailingPressedIconButton:
id: chevron
icon: "chevron-right"
on_release: app.tap_expansion_chevron(root, chevron)
MDExpansionPanelContent:
orientation: "vertical"
padding: "12dp", 0, "12dp", "12dp"
md_bg_color: self.theme_cls.surfaceContainerLowestColor
MDLabel:
text: "Channel information"
adaptive_height: True
padding_x: "16dp"
padding_y: "12dp"
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowestColor
MDListItemLeadingIcon:
icon: "email"
MDListItemHeadlineText:
text: "Email"
MDListItemSupportingText:
text: "kivydevelopment@gmail.com"
MDListItem:
theme_bg_color: "Custom"
md_bg_color: self.theme_cls.surfaceContainerLowestColor
MDListItemLeadingIcon:
icon: "instagram"
MDListItemHeadlineText:
text: "Instagram"
MDListItemSupportingText:
text: "Account"
MDListItemTertiaryText:
text: "www.instagram.com/KivyMD"
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
ScrollView:
size_hint_x: .5
pos_hint: {"center_x": .5, "center_y": .5}
MDList:
id: container
'''
class ExpansionPanelItem(MDExpansionPanel):
...
class TrailingPressedIconButton(
ButtonBehavior, RotateBehavior, MDListItemTrailingIcon
):
...
class Example(MDApp):
2024-09-15 12:12:16 +00:00
def on_start(self):
2024-09-15 17:57:02 +00:00
async def set_panel_list():
for i in range(12):
await asynckivy.sleep(0)
self.root.ids.container.add_widget(ExpansionPanelItem())
asynckivy.start(set_panel_list())
def build(self):
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
def tap_expansion_chevron(
self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton
):
Animation(
padding=[0, dp(12), 0, dp(12)]
if not panel.is_open
else [0, 0, 0, 0],
d=0.2,
).start(panel)
panel.open() if not panel.is_open else panel.close()
panel.set_chevron_down(
chevron
) if not panel.is_open else panel.set_chevron_up(chevron)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel-example-with-scroll-view.gif
2024-09-15 12:12:16 +00:00
:align: center
2024-09-15 17:57:02 +00:00
API break
=========
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
1.2.0 version
-------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDExpansionPanel(
icon="icon.png",
content=Content(), # content of panel
panel_cls=MDExpansionPanelThreeLine( # content of header
text="Text",
secondary_text="Secondary text",
tertiary_text="Tertiary text",
)
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
2.0.0 version
-------------
2024-09-15 12:12:16 +00:00
.. code-block:: python
2024-09-15 17:57:02 +00:00
MDExpansionPanel:
MDExpansionPanelHeader:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
# Content of header.
[...]
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDExpansionPanelContent:
# Content of panel.
[...]
2024-09-15 12:12:16 +00:00
"""
__all__ = (
"MDExpansionPanel",
2024-09-15 17:57:02 +00:00
"MDExpansionPanelContent",
"MDExpansionPanelHeader",
2024-09-15 12:12:16 +00:00
)
import os
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
2024-09-15 17:57:02 +00:00
from kivy.properties import (
NumericProperty,
ObjectProperty,
StringProperty,
BooleanProperty,
)
from kivy.uix.boxlayout import BoxLayout
2024-09-15 12:12:16 +00:00
from kivymd import uix_path
2024-09-15 17:57:02 +00:00
from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import BackgroundColorBehavior, DeclarativeBehavior
2024-09-15 12:12:16 +00:00
with open(
os.path.join(uix_path, "expansionpanel", "expansionpanel.kv"),
encoding="utf-8",
) as kv_file:
Builder.load_string(kv_file.read())
2024-09-15 17:57:02 +00:00
class MDExpansionPanelContent(
DeclarativeBehavior, ThemableBehavior, BackgroundColorBehavior, BoxLayout
):
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Implements a container for panel content.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
For more information, see in the
2024-09-15 17:57:02 +00:00
:class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
:class:`~kivymd.theming.ThemableBehavior` and
:class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and
:class:`~kivy.uix.boxlayout.BoxLayout`
classes documentation.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
class MDExpansionPanelHeader(DeclarativeBehavior, BoxLayout):
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Implements a container for the content of the panel header.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
For more information, see in the
2024-09-15 17:57:02 +00:00
:class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
:class:`~kivy.uix.boxlayout.BoxLayout`
classes documentation.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
# TODO: Add a successor from kivymd.uix.behaviors.motion_behavior.MotionBase
# to the MDExpansionPanel class to control the properties of the panel
# opening/closing animation.
class MDExpansionPanel(DeclarativeBehavior, BoxLayout):
2024-09-15 12:12:16 +00:00
"""
Expansion panel class.
For more information, see in the
2024-09-15 17:57:02 +00:00
:class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
:class:`~kivy.uix.boxlayout.BoxLayout`
classes documentation.
2024-09-15 12:12:16 +00:00
:Events:
:attr:`on_open`
2024-09-15 17:57:02 +00:00
Fired when a panel is opened.
2024-09-15 12:12:16 +00:00
:attr:`on_close`
2024-09-15 17:57:02 +00:00
Fired when a panel is closed.
2024-09-15 12:12:16 +00:00
"""
opening_transition = StringProperty("out_cubic")
"""
The name of the animation transition type to use when animating to
the :attr:`state` `'open'`.
:attr:`opening_transition` is a :class:`~kivy.properties.StringProperty`
and defaults to `'out_cubic'`.
"""
opening_time = NumericProperty(0.2)
"""
The time taken for the panel to slide to the :attr:`state` `'open'`.
:attr:`opening_time` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
closing_transition = StringProperty("out_sine")
"""
The name of the animation transition type to use when animating to
the :attr:`state` 'close'.
:attr:`closing_transition` is a :class:`~kivy.properties.StringProperty`
and defaults to `'out_sine'`.
"""
closing_time = NumericProperty(0.2)
"""
The time taken for the panel to slide to the :attr:`state` `'close'`.
:attr:`closing_time` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
2024-09-15 17:57:02 +00:00
is_open = BooleanProperty(False)
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
The panel is open or closed.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
:attr:`is_open` is a :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
_header = ObjectProperty() # MDExpansionPanelHeader object
_content = ObjectProperty() # MDExpansionPanelContent object
# Height of the MDExpansionPanelContent widget.
_original_content_height = NumericProperty()
_allow_add_content = False
_panel_is_process_opening = False
2024-09-15 12:12:16 +00:00
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.register_event_type("on_open")
self.register_event_type("on_close")
2024-09-15 17:57:02 +00:00
def on_open(self, *args) -> None:
"""Fired when a panel is opened."""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_close(self, *args) -> None:
"""Fired when a panel is closed."""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def set_chevron_down(self, instance) -> None:
2024-09-15 12:12:16 +00:00
"""Sets the chevron down."""
2024-09-15 17:57:02 +00:00
Animation(rotate_value_angle=-90, d=self.opening_time).start(instance)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def set_chevron_up(self, instance) -> None:
2024-09-15 12:12:16 +00:00
"""Sets the chevron up."""
2024-09-15 17:57:02 +00:00
Animation(rotate_value_angle=0, d=self.closing_time).start(instance)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def close(self, *args) -> None:
"""
Method closes the panel.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `close_panel` to `close` method.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def set_content_height(*args):
anim_height = Animation(
height=0,
t=self.opening_transition,
d=self.opening_time,
)
anim_height.bind(
on_complete=lambda *args: self.remove_widget(self._content)
)
anim_height.start(self._content)
self.is_open = False
self.dispatch("on_close")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
anim_opacity = Animation(
opacity=0,
t=self.opening_transition,
d=self.opening_time,
2024-09-15 12:12:16 +00:00
)
2024-09-15 17:57:02 +00:00
anim_opacity.bind(on_complete=set_content_height)
anim_opacity.start(self._content)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def open(self, *args) -> None:
"""
Method opens a panel.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `open_panel` to `open` method.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def set_content_opacity(*args):
Animation(
opacity=1,
t=self.opening_transition,
d=self.opening_time,
).start(self._content)
self.is_open = True
self._panel_is_process_opening = False
self.dispatch("on_open")
if not self._panel_is_process_opening:
self._allow_add_content = True
self._panel_is_process_opening = True
self.add_widget(self._content)
anim_height = Animation(
height=self._original_content_height,
t=self.opening_transition,
d=self.opening_time,
)
anim_height.bind(on_complete=set_content_opacity)
anim_height.start(self._content)
2024-09-15 12:12:16 +00:00
def add_widget(self, widget, index=0, canvas=None):
2024-09-15 17:57:02 +00:00
if isinstance(widget, MDExpansionPanelHeader):
self._header = widget
return super().add_widget(widget)
elif (
isinstance(widget, MDExpansionPanelContent)
and not self._allow_add_content
2024-09-15 12:12:16 +00:00
):
2024-09-15 17:57:02 +00:00
self._content = widget
Clock.schedule_once(self._set_content_height, 0.8)
elif (
isinstance(widget, MDExpansionPanelContent)
and self._allow_add_content
):
return super().add_widget(widget)
def _set_content_height(self, *args):
self._original_content_height = self._content.height - dp(88)
self._content.height = 0