Timson
Timson

Reputation: 19

How can I rotate and animate a MDLabel on adifferent axis?

I have this code that creates a MDLabel with ButtonBehavior and RotateBehavior. When the rotate_value_angle is set to 0, I can animate the MDLabel's height from 500 to 250. When I change the angle to 90, the MDLabel rotates anti-clockwise, as expected.

The problem I'm experiencing is that with the rotate_value_angle at 90 degrees, both the height and width of the MDLabel are animated. I want to animate the MDLabel's 'height', which would be the left side of it, to move from left to right while maintaining its anchor point at the bottom-right corner.

Essentially, the movement of the MDLabel should be similar to the movement when the rotate_value_angle is set at 0 but with the phone tilted 90 degrees anti-clockwise.

Thanks in advance.

Here's my Kivy


MDScreen:
    RotateLabel:
        id: label
        size_hint: None, None
        size: 300, 500
        pos: 210, 470
        text: "Hello World!"
        on_release: app.change_rotate(self)
        md_bg_color: "red"


Python


class RotateLabel(ButtonBehavior, RotateBehavior, MDLabel):
    pass

class Test(MDApp):
    def build(self):

        return Builder.load_string(kv)

    def change_rotate(self, instance_button: RotateLabel) -> None:
        # angle = choice([i * 45 for i in range(8)])

        anim = Animation(
            # rotate_value_angle = 0
            rotate_value_angle = 90, 
            d = 1)
        
        anim.bind(on_start = self.change_label_height)

        anim.start(instance_button)

    def change_label_height(self, *args):
        label = self.root.ids.label

        if label.size == [300, 500]:
            anim = Animation(
                height = 250,
                d = 2
            )

            anim.start(label)
        else:
            anim = Animation(
                height = 500,
                d = 2
            )

            anim.start(label)

Test().run()

Upvotes: 0

Views: 22

Answers (1)

John Anderson
John Anderson

Reputation: 38822

I think the problem is that RotateBehavior rotates the widget about its center, which causes the behavior you are seeing. There doesn't seem to be any way to change the rotation origin when using RotateBehavior. You can change your RotateLabel definition without using RotateBehavior like this:

class RotateLabel(ButtonBehavior, MDLabel):
    rotate_value_angle = NumericProperty(0)
    rot_matrix = ObjectProperty(Matrix())

    def on_rotate_value_angle(self, *args):
        self.rot_matrix.identity()
        self.rot_matrix.rotate(radians(-self.rotate_value_angle), 0, 0, 1)

    def collide_point(self, x, y):
        if self.rotate_value_angle == 0:
            return super(RotateLabel, self).collide_point(x, y)
        else:
            x1 = x - self.x
            y1 = y - self.y
            x2, y2, z2 = self.rot_matrix.transform_point(x1, y1, 0)
            x3 = x2 + self.x
            y3 = y2 + self.y
            return self.x <= x3 <= self.right and self.y <= y3 <= self.top

The above code handles the rotation and modifies the collide_point() method (which is used for button clicks) to account for the rotation.

The kv must also be modified for this to work:

MDScreen:
    RotateLabel:
        id: label
        size_hint: None, None
        size: 300, 500
        pos: 210, 470
        text: "Hello World!"
        on_release: app.change_rotate(self)
        md_bg_color: "red"
        canvas.before:
            PushMatrix:
            Rotate:
                angle: self.rotate_value_angle
                axis: 0, 0, 1
                origin: self.pos
        canvas.after:
            PopMatrix:

The above code does the rotation about the pos of the RotateLabel instead of its center.

Upvotes: 0

Related Questions