How to create Dropdown animation in Kivy

Question:

I’m trying to animate a dropdown symbol to rotate down (when the dropdown option is open) and revert back to it’s original position (when dropdown option closes). Please find this attached screenshot.

Here’s my py file:

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 DropdownBtnAnimation(self, wid):
        ani = Animation(angle=-90, duration=0.02)
        ani.start(wid)
                


BabyGenderFinder().run()

kv file:

#: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
    on_release: self.color = hex("ECE4F5") ; app.DropdownBtnAnimation(self.ids.dropdown_sign)

    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>:
    canvas.before:
        Color:
            rgba: hex("#1F1F73")
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: [0, 0, 6, 6]
    max_height: 200

                                                                    # 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]

I can make the button rotate down, but I can’t seem to make the button go back to normal when dropdown options closes. I also want some actions done when I close Spinner widget (ex: If I clicked outside the dropdown options list when the list is open, I wanna trigger some actions)

I’m fairly new with kivy. Please help me.

Asked By: StevenHaven

||

Answers:

In your kv, you can set the angle back to 0 when the text is changed on the DropdownMenu:

            DropdownMenu:
                id: month
                text: 'Select'
                values: [month for month, x in app.temp_db.items()]
                on_text: self.ids.dropdown_sign.angle=0

Or, you can eliminate the animation completely, and just set the angle of the icon to depend on whether the DropdownMenu is open:

MDIconButton:
    id: dropdown_sign
    center_x: self.parent.center_x + 110
    center_y: self.parent.center_y
    # angle: 0
    canvas.before:
        PushMatrix
        Rotate:
            angle: 90 if root.is_open else 0  # adjusts angle of icon
            axis: 0, 0, 1
            origin: self.center
    canvas.after:
        PopMatrix
    Image:            
        source: "images/dropdown.png"
        size_hint: None, None
        size: 20, 20
Answered By: John Anderson
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.