Reputation: 344
So basically I'm trying to use Animation with add_widget and remove_widget to make the app look smoother.
The problem with the default BoxLayout is that when you remove_widget, the widget just disappears, and then fills gaps with the rest of the widgets instantly.
For example, when you click the "x" button below the widget
The glass of wine disappeared and auto-fit without any smooth animation
I just wonder if is there any way to do this?
Here the code used for the image example:
from kivymd.app import MDApp
from kivymd.uix.relativelayout import MDRelativeLayout
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.properties import StringProperty
from kivy.metrics import dp
from kivy.lang.builder import Builder
KV="""
<ListItems>:
ScrollView:
do_scroll_y: False
MDBoxLayout:
id: order_list
padding: dp(10)
size_hint:None,None
width: self.minimum_width
height: dp(150)
Button:
text: "ADD PUDDING"
size_hint: None, None
size: dp(110), dp(60)
pos_hint:{"center_x":.2, "center_y":.1}
on_press:
root.add_item="ReWorkLayout/items/pudding.png"
Button:
text: "ADD WINE"
size_hint: None, None
size: dp(110), dp(60)
pos_hint:{"center_x":.8, "center_y":.1}
on_press:
root.add_item="ReWorkLayout/items/wine.png"
<Item>:
id: item
source: root.image
size_hint: None,None
size: dp(130),dp(130)
MDIconButton:
icon: "close"
user_font_size: dp(35)
pos: item.pos[0] + item.width/2 - self.width/2,item.pos[1] - self.height
on_press:
app.root.ids.order_list.remove_widget(root)
"""
class ListItems(MDRelativeLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
@property
def add_item(self):
return "nothing here lul."
@add_item.setter
def add_item(self,image):
i = Item()
i.image=image
self.ids.order_list.add_widget(i)
def remove_item(self,item):
self.ids.order_list.remove_widget(item)
class Item(Image):
image=StringProperty()
class TestRun(MDApp):
def build(self):
self.kv=Builder.load_string(KV)
return ListItems()
if __name__=="__main__":
TestRun().run()
Upvotes: 0
Views: 555
Reputation: 2908
You can use class Animation to bring a nice (visually pleasing) effect on removal of some widget.
The idea is to bring down any of widget's size
(or sometimes size_hint
) property to zero or sufficiently small value (that will be visually negligible) and only then remove the widget. You can also use prop. opacity
for even smoother experience.
Below is the implementation of this idea.
First in your kvlang
of Item
,
on_press:
app.root.remove_item(item)
# app.root.ids.order_list.remove_widget(root)
Then in method remove_item
,
def remove_item(self, item):
# Create an animation instance with properties (that will be animated)
# like (widget's) width, opacity etc. with their resp. target values.
anim = Animation(width = 0, opacity = 0, d = 0.5)
# Bind the removal callback which will take place
# as soon as the animation is completed.
anim.bind(on_complete=lambda *args : self.ids.order_list.remove_widget(item))
# Now start with the target widget.
anim.start(item)
Upvotes: 1
Reputation: 39152
As @ApuCoder mentioned, you can do this by using Animation
. In your App
class you can add methods:
def animate_widget_removal(self, wid):
# animate shrinking widget width
anim = Animation(width=0)
anim.bind(on_complete=self.do_actual_remove)
anim.start(wid)
def do_actual_remove(self, anim, wid):
# actually remove the shrunken widget
self.root.ids.order_list.remove_widget(wid)
And reference the animate_widget_removal()
method in your kv
:
on_press:
app.animate_widget_removal(root)
# app.root.ids.order_list.remove_widget(root)
And you can animate the addition of widgets by animating the opacity
, in the add_item()
method:
def add_item(self,image):
i = Item()
i.image=image
i.opacity = 0
self.ids.order_list.add_widget(i)
anim = Animation(opacity=1)
anim.start(i)
Of course, you can animate different or more properties in either case.
Upvotes: 1