Kivy中Dropdown箭头旋转动画实现及Spinner关闭事件处理
解决Kivy Dropdown箭头旋转复原及关闭触发问题
核心思路
要实现箭头展开旋转、关闭复原,关键是监听Dropdown的关闭事件(on_dismiss),在事件触发时执行反向动画;同时通过Dropdown和Spinner的关联,确保所有关闭操作(包括点击外部区域)都能触发回调。
修改步骤
1. 更新Python代码
新增箭头还原动画方法,拆分展开/关闭动画逻辑:
from kivy.lang.builder import Builder from kivymd.app import MDApp from kivy.uix.screenmanager import Screen, ScreenManager from kivy.utils import get_color_from_hex as hex from kivy.animation import Animation Builder.load_file("dropdowns_and_btns.kv") kv = """ #:import hex kivy.utils.get_color_from_hex #:import FadeTransition kivy.uix.screenmanager.FadeTransition MyScreenManager: transition: FadeTransition(duration=0) IntroPage: LandingPage: ResultPage: <IntroPage> MDScreen: md_bg_color: hex("#07074D") MDLabel: text: "BGF" color: hex("#ECE4F5") font_size: 36 pos_hint: {"center": (0.5, 0.7)} halign: "center" RoundedGradientButton: text: "START" font_size: 20 size_hint: 0.3, 0.08 pos_hint: {"center": (0.5, 0.3)} on_release: app.root.current = "landing_page" <LandingPage> name: "landing_page" MDScreen: md_bg_color: hex("#07074D") MDLabel: icon_color: 1, 0, 1, 1 text: "Please select" pos_hint: {"center_y": 0.9} halign: "center" font_size: 32 color: hex("#ECE4F5") # Dropdown Label MDFloatLayout: size_hint: 0.75, 0.3 pos_hint: {"center": (0.5, 0.5)} BoxLayout size_hint: 0.5, 0.9 pos_hint: {"center": (0.26, 0.9)} MDLabel: text: "Month" color: hex("#ECE4F5") BoxLayout size_hint: 0.5, 0.9 pos_hint: {"center": (0.79, 0.9)} MDLabel: text: "Year" color: hex("#ECE4F5") # Dropdown Button MDGridLayout: cols: 2 size_hint: 1, 0.3 pos_hint: {"center": (0.5, 0.65)} spacing: 30 DropdownMenu: id: month text: 'Select' values: [month for month, x in app.temp_db.items()] on_text: self.text DropdownMenu: id: year text: 'Select' values: [f"{year}" for year in range(18, 46)] on_text: self.text # Find now button RoundedGradientButton: text: "FIND NOW" font_size: 16 size_hint: 0.25, 0.25 pos_hint: {"center": (0.5, 0.15)} <ResultPage> name: "result_page" MDScreen: md_bg_color: hex("#07074D") MDLabel: id: result_prefix_label text: "Congratulations!" color: hex("#ECE4F5") font_size: 20 pos_hint: {"center": (0.5, 0.7)} halign: "center" MDLabel: id: result_label color: hex("#ECE4F5") font_size: 40 pos_hint: {"center": (0.5, 0.6)} halign: "center" Button: background_normal: "" background_color: 0, 0, 0, 0 pos_hint: {"center": (0.5, 0.3)} on_press: app.root.current = "landing_page" Image: source: "images/reload.png" center_x: self.parent.center_x center_y: self.parent.center_y size_hint_x: None height: 50 """ class IntroPage(Screen): pass class LandingPage(Screen): pass class ResultPage(Screen): pass class MyScreenManager(ScreenManager): pass class BabyGenderFinder(MDApp): temp_db = {"January": 1, "February": 2, "March": 3, "April": 4, "May": 5} def build(self): return Builder.load_string(kv) def dropdown_expand_animation(self, wid): ani = Animation(angle=-90, duration=0.2) ani.start(wid) def dropdown_collapse_animation(self, wid): ani = Animation(angle=0, duration=0.2) ani.start(wid) BabyGenderFinder().run()
2. 更新KV文件
绑定Dropdown关闭事件,关联Spinner与Dropdown的引用,同步颜色与动画:
#:import hex kivy.utils.get_color_from_hex #:import Factory kivy.factory.Factory # Drop down button setting <DropdownMenu@Spinner> dropdown_cls: Factory.CustomDropdown option_cls: Factory.DropdownOptions color: hex("#87828C") font_name: "fonts/Poppins-Medium.ttf" background_normal: "" background_color: 0, 0, 0, 0 # 展开时触发动画和颜色变化,同时绑定Spinner引用到Dropdown on_release: self.color = hex("#ECE4F5") app.dropdown_expand_animation(self.ids.dropdown_sign) if not self._dropdown: self._dropdown = self.dropdown_cls() self._dropdown.spinner_ref = self canvas.before: Color: rgba: hex("#111140") RoundedRectangle: size: self.size pos: self.pos radius: [6] Color: rgba: hex("#1F1F73") Line: width: 1.25 rounded_rectangle: self.x, self.y, self.width, self.height, 6, 6, 6, 6, 100 MDIconButton: id: dropdown_sign center_x: self.parent.center_x + 110 center_y: self.parent.center_y angle: 0 canvas.before: PushMatrix Rotate: angle: self.angle axis: 0, 0, 1 origin: self.center canvas.after: PopMatrix Image: source: "images/dropdown.png" size_hint: None, None size: 20, 20 # Drop down options setting <DropdownOptions@SpinnerOption> color: hex("#ECE4F5") font_name: "fonts/Poppins-Regular.ttf" background_normal: "" background_color: 0, 0, 0, 0 # Drop down options separator setting canvas: Color: rgba: hex("#3D3D99") Line: width: 1 points: self.x+10, self.y, self.width-10, self.y <CustomDropdown@DropDown>: spinner_ref: None # 存储对应的Spinner引用 canvas.before: Color: rgba: hex("#1F1F73") RoundedRectangle: size: self.size pos: self.pos radius: [0, 0, 6, 6] max_height: 200 # 关闭Dropdown时触发还原动画和颜色恢复 on_dismiss: if self.spinner_ref: app.dropdown_collapse_animation(self.spinner_ref.ids.dropdown_sign) self.spinner_ref.color = hex("#87828C") # Gradient button settings <RoundedGradientButton@Button> background_normal: "" background_color: 0,0,0,0 font_name: "fonts/Poppins-Medium.ttf" on_press: self.size_hint = self.size_hint_x/1.05, self.size_hint_y/1.05 on_release: self.size_hint = self.size_hint_x*1.05, self.size_hint_y*1.05 canvas.before: Color: rgba: 1, 1, 1, 1 RoundedRectangle: source: "button_bg.png" size: self.size pos: self.pos radius: [self.size[1]/1.92]
关键说明
- 全局关闭监听:
CustomDropdown的on_dismiss事件会覆盖所有关闭场景(点击选项、点击外部区域),确保箭头总能复原。 - 组件关联:通过
spinner_ref将Dropdown与对应的Spinner绑定,避免操作错误的箭头组件。 - 动画优化:将动画时长调整为0.2秒,让旋转过渡更平滑自然。
内容的提问来源于stack exchange,提问作者StevenHaven
相关产品推荐
相关产品推荐

