"""
Components/ResponsiveLayout
===========================
.. versionadded:: 1.0.0
.. rubric:: Responsive design is a graphic user interface (GUI) design
approach used to create content that adjusts smoothly to various screen
sizes.
.. raw:: html
The :class:`~MDResponsiveLayout` class does not reorganize your UI. Its task
is to track the size of the application screen and, depending on this size,
the :class:`~MDResponsiveLayout` class selects which UI layout should be
displayed at the moment: mobile, tablet or desktop. Therefore, if you want to
have a responsive view some kind of layout in your application, you should
have three KV files with UI markup for three platforms.
You need to set three parameters for the :class:`~MDResponsiveLayout` class
:attr:`~MDResponsiveLayout.mobile_view`,
:attr:`~MDResponsiveLayout.tablet_view` and
:attr:`~MDResponsiveLayout.desktop_view`. These should be Kivy or KivyMD
widgets.
Usage responsive
----------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.responsivelayout import MDResponsiveLayout
from kivymd.uix.screen import MDScreen
KV = '''
halign: "center"
CommonComponentLabel:
text: "Mobile"
CommonComponentLabel:
text: "Table"
CommonComponentLabel:
text: "Desktop"
ResponsiveView:
'''
class CommonComponentLabel(MDLabel):
pass
class MobileView(MDScreen):
pass
class TabletView(MDScreen):
pass
class DesktopView(MDScreen):
pass
class ResponsiveView(MDResponsiveLayout, MDScreen):
def __init__(self, **kw):
super().__init__(**kw)
self.mobile_view = MobileView()
self.tablet_view = TabletView()
self.desktop_view = DesktopView()
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/responsive-usage.gif
:align: center
.. note:: Use common components for platform layouts (mobile, tablet, desktop views).
As shown in the example above, such a common component is the
`CommonComponentLabel` widget.
Perhaps you expected more from the :class:`~MDResponsiveLayout` widget, but
even `Flutter` uses a similar approach to creating a responsive UI.
You can also use the `commands `_
provided to you by the developer tools to create a project with an responsive
design.
"""
from kivy.event import EventDispatcher
from kivy.properties import ObjectProperty
from kivymd.uix.controllers import WindowController
class MDResponsiveLayout(EventDispatcher, WindowController):
"""
:Events:
:attr:`on_change_screen_type`
Called when the screen type changes.
"""
mobile_view = ObjectProperty()
"""
Mobile view. Must be a Kivy or KivyMD widget.
:attr:`mobile_view` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `None`.
"""
tablet_view = ObjectProperty()
"""
Tablet view. Must be a Kivy or KivyMD widget.
:attr:`tablet_view` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `None`.
"""
desktop_view = ObjectProperty()
"""
Desktop view. Must be a Kivy or KivyMD widget.
:attr:`desktop_view` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `None`.
"""
_current_device_type = ""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.register_event_type("on_change_screen_type")
def on_change_screen_type(self, *args):
"""Called when the screen type changes."""
def on_size(self, *args) -> None:
"""Called when the application screen size changes."""
super().on_size(*args)
self.set_screen()
if self._current_device_type != self.real_device_type:
self._current_device_type = self.real_device_type
def set_screen(self) -> None:
"""
Sets the screen according to the type of application screen size:
mobile/tablet or desktop view.
"""
if self.real_device_type != self._current_device_type:
self.clear_widgets()
if self.mobile_view and self.tablet_view and self.desktop_view:
if self.real_device_type == "mobile":
self.add_widget(self.mobile_view)
elif self.real_device_type == "tablet":
self.add_widget(self.tablet_view)
elif self.real_device_type == "desktop":
self.add_widget(self.desktop_view)
self.dispatch("on_change_screen_type", self.real_device_type)