Last active
June 16, 2022 01:39
-
-
Save tshirtman/908d299846b5195f27fb9ae1ab78d4ba to your computer and use it in GitHub Desktop.
use a proxy widget to animate items of a recycleview without leaking on other widgets.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from copy import copy | |
from kivy.app import App | |
from kivy.clock import triggered | |
from kivy.lang import Builder | |
from kivy.animation import Animation | |
from kivy.factory import Factory as F | |
from kivy.properties import ( | |
ObjectProperty, ListProperty | |
) | |
KV = ''' | |
<Item>: | |
index: None | |
animation_proxy: None | |
on_release: app.animate_item(self.index) | |
RecycleView: | |
data: app.data | |
viewclass: 'Item' | |
RecycleBoxLayout: | |
orientation: 'vertical' | |
size_hint: 1, None | |
height: self.minimum_height | |
default_size_hint: 1, None | |
default_size: 0, dp(40) | |
''' | |
class Item(F.Button): | |
animation_proxy = ObjectProperty(allownone=True) | |
_animation_proxy = None | |
def update_opacity(self, proxy, opacity): | |
self.opacity = opacity | |
def on_animation_proxy(self, *args): | |
if self._animation_proxy: | |
self._animation_proxy.unbind(opacity=self.update_opacity) | |
self._animation_proxy = self.animation_proxy | |
if self.animation_proxy: | |
self.opacity = self.animation_proxy.opacity | |
self.animation_proxy.bind(opacity=self.update_opacity) | |
else: | |
self.opacity = 1 | |
class Application(App): | |
data = ListProperty() | |
def build(self): | |
self.data = [ | |
{'index': i, 'text': 'hello {}'.format(i), 'animation_proxy': None} | |
for i in range(1000) | |
] | |
return Builder.load_string(KV) | |
def update_time(self, dt): | |
self.time += dt | |
@triggered(timeout=0.05) | |
def animate_item(self, index): | |
proxy = F.Widget(opacity=1) | |
item = copy(self.data[index]) | |
animation = ( | |
Animation(opacity=0, d=.1, t='out_quad') | |
+ Animation(opacity=1, d=5, t='out_quad') | |
) | |
animation.bind(on_complete=lambda *x: self.reset_animation(item)) | |
item['animation_proxy'] = proxy | |
self.data[index] = item | |
animation.start(proxy) | |
def reset_animation(self, item): | |
# animation is complete, widget should be collected | |
item['animation_proxy'] = None | |
if __name__ == "__main__": | |
Application().run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment