93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
from kivy.animation import Animation
|
||
|
from kivy.clock import Clock
|
||
|
from kivy.core.window import Window
|
||
|
from kivy.lang import Builder
|
||
|
from kivy.metrics import dp
|
||
|
from kivy.properties import OptionProperty, NumericProperty, StringProperty, \
|
||
|
BooleanProperty, ListProperty
|
||
|
from kivy.uix.boxlayout import BoxLayout
|
||
|
from kivy.uix.relativelayout import RelativeLayout
|
||
|
|
||
|
Builder.load_string("""
|
||
|
#: import Window kivy.core.window.Window
|
||
|
<SlidingPanel>
|
||
|
orientation: 'vertical'
|
||
|
size_hint_x: None
|
||
|
width: dp(320)
|
||
|
x: -1 * self.width if self.side == 'left' else Window.width
|
||
|
|
||
|
<PanelShadow>
|
||
|
canvas:
|
||
|
Color:
|
||
|
rgba: root.color
|
||
|
Rectangle:
|
||
|
size: root.size
|
||
|
""")
|
||
|
|
||
|
|
||
|
class PanelShadow(BoxLayout):
|
||
|
color = ListProperty([0, 0, 0, 0])
|
||
|
|
||
|
|
||
|
class SlidingPanel(BoxLayout):
|
||
|
anim_length_close = NumericProperty(0.3)
|
||
|
anim_length_open = NumericProperty(0.3)
|
||
|
animation_t_open = StringProperty('out_sine')
|
||
|
animation_t_close = StringProperty('out_sine')
|
||
|
side = OptionProperty('left', options=['left', 'right'])
|
||
|
|
||
|
_open = False
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
super(SlidingPanel, self).__init__(**kwargs)
|
||
|
self.shadow = PanelShadow()
|
||
|
Clock.schedule_once(lambda x: Window.add_widget(self.shadow,89), 0)
|
||
|
Clock.schedule_once(lambda x: Window.add_widget(self,90), 0)
|
||
|
|
||
|
def toggle(self):
|
||
|
Animation.stop_all(self, 'x')
|
||
|
Animation.stop_all(self.shadow, 'color')
|
||
|
if self._open:
|
||
|
if self.side == 'left':
|
||
|
target_x = -1 * self.width
|
||
|
else:
|
||
|
target_x = Window.width
|
||
|
|
||
|
sh_anim = Animation(duration=self.anim_length_open,
|
||
|
t=self.animation_t_open,
|
||
|
color=[0, 0, 0, 0])
|
||
|
sh_anim.start(self.shadow)
|
||
|
self._get_main_animation(duration=self.anim_length_close,
|
||
|
t=self.animation_t_close,
|
||
|
x=target_x,
|
||
|
is_closing=True).start(self)
|
||
|
self._open = False
|
||
|
else:
|
||
|
if self.side == 'left':
|
||
|
target_x = 0
|
||
|
else:
|
||
|
target_x = Window.width - self.width
|
||
|
Animation(duration=self.anim_length_open, t=self.animation_t_open,
|
||
|
color=[0, 0, 0, 0.5]).start(self.shadow)
|
||
|
self._get_main_animation(duration=self.anim_length_open,
|
||
|
t=self.animation_t_open,
|
||
|
x=target_x,
|
||
|
is_closing=False).start(self)
|
||
|
self._open = True
|
||
|
|
||
|
def _get_main_animation(self, duration, t, x, is_closing):
|
||
|
return Animation(duration=duration, t=t, x=x)
|
||
|
|
||
|
def on_touch_down(self, touch):
|
||
|
# Prevents touch events from propagating to anything below the widget.
|
||
|
super(SlidingPanel, self).on_touch_down(touch)
|
||
|
if self.collide_point(*touch.pos) or self._open:
|
||
|
return True
|
||
|
|
||
|
def on_touch_up(self, touch):
|
||
|
if not self.collide_point(touch.x, touch.y) and self._open:
|
||
|
self.toggle()
|
||
|
return True
|
||
|
super(SlidingPanel, self).on_touch_up(touch)
|