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 :)