As someone asked how to do such thing in kivy, i spent some time writting it, and as i (sadly) don’t blog on kivy often (if ever?), and since i think this example is quite telling about how kivy make such things quite easy, let’s talk a bit about this code.
To put things in context, what we want is the bar at the top of the android phones, that one can pull down to see notifications, this one is semi transparent and goes over the normal screen.
So, here is the code. first the kv part:
FloatLayout:
FloatLayout:
# placeholder for the "normal screen"
Label:
center: root.center
text: 'test content'
size_hint: None, None
size: self.texture_size
ScrollView:
# container for the "notifications"
y: dg.top # let's stick it to the top
x: root.x # and to the left
size_hint_y: None
do_scroll_x: False # only vertical scrolling
do_scroll_y: True
# most of the magic is there, auto adjust size to follow the draggable label
height: root.top - dg.y
# let's put a nearly opaque black background
canvas:
Color:
rgba: 0, 0, 0, .8
Rectangle:
pos: self.pos
size: self.size
# the actual notification container, with placeholder content
BoxLayout:
size_hint_y: None
height: 1000
orientation: 'vertical'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
Label:
text: 'test'
# the draggable label, which behaviour is defined in python file
DraggableLabel:
# some decoration behind the text
canvas.before:
Color:
rgba: 0, 0, 0, 1
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: .5, .5, .5, 1
Rectangle:
pos: self.pos
size: self.width, 1
size_hint_y: None
top: root.top
# assign its id to "dg" so we can reference it elsewhere
id: dg
height: '20pt'
text: 'drag me'
then the python part
from kivy.app import App
from kivy.uix.label import Label
from kivy.animation import Animation
class DraggableLabel(Label):
'''A label you can drag upside-down'''
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
# assure ourselves we will get the updates of this motion
touch.grab(self)
return True
return super(DraggableLabel, self).on_touch_down(touch)
def on_touch_move(self, touch):
if touch.grab_current is self:
# really straightforward...
self.y = touch.y
return True
return super(DraggableLabel, self).on_touch_move(touch)
def on_touch_up(self, touch):
if touch.grab_current is self:
# check if the movement direction was up or down
if touch.dy < 0:
a = Animation(y=0) # down? put the bar all the way down
else:
a = Animation(top=self.parent.top) # up? put it at the top
a.start(self) # actually start the animation
return True
return super(DraggableLabel, self).on_touch_up(touch)
class TabApp(App):
pass
TabApp().run()
I think it doesn’t really need more explanations, the DraggableLabel is looking for touch events that are for it, first if they are on it, then if they are grabbed by itself, and move accordingly, and the kv auto adjust the size of the ScrollView to take all the distance between top of the screen and top of the DraggableLabel.
Of course, if things are not clear, feel free to ask questions :)