text: '''How to use Animation with RecycleView items?
  
  In case you really want to use the Animation class with RecycleView, you'll
  likely encounter an issue, as widgets are moved around, they are used to
  represent different items, so an animation on a specific item is going to
  affect others, and this will lead to really confusing results.
  
  This example works around that by creating a "proxy" widget for the animation,
  and, by putting it in the data, allowing the displayed widget to mimic the
  animation. As the item always refers to its proxy, whichever widget is used to
  display the item will keep in sync with the animation.
  
  '''
  from copy import copy
  
  from kivy.app import App
  from kivy.clock import triggered
  from kivy.lang import Builder
  from kivy.uix.widget import Widget
  from kivy.animation import Animation
  from kivy.uix.button import Button
  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(Button):
      animation_proxy = ObjectProperty(allownone=True)
      _animation_proxy = None
  
      def update_opacity(self, proxy, opacity):
          # sync one animated property to the value in the proxy
          self.opacity = opacity
  
      def on_animation_proxy(self, *args):
          """When we create an animation proxy for an item, we need to bind to
          the animated property to update our own.
          """
          if self._animation_proxy:
              self._animation_proxy.unbind(opacity=self.update_opacity)
  
          self._animation_proxy = self.animation_proxy
          if self.animation_proxy:
              # when we are assigned an animation_proxy, sync our properties to
              # the animated version.
              self.opacity = self.animation_proxy.opacity
              self.animation_proxy.bind(opacity=self.update_opacity)
          else:
              # if we lose our animation proxy, we need to reset the animated
              # property to their default values.
              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)
  
      # the triggered decorator allows delaying the animation until after the
      # blue effect on the button is removed, to avoid a flash as widgets gets
      # reordered when that happens
      @triggered(timeout=0.05)
      def animate_item(self, index):
          # the animation we actually want to do on the item, note that any
          # property animated here needs to be synchronised from the proxy to the
          # animated widget (in on_animation_proxy and using methods for each
          # animation)
          proxy = 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 garbage collected
          item['animation_proxy'] = None
  
  
  if __name__ == "__main__":
      Application().run()
  