2

Problem

I am building in app (with Kivy) which renders some custom widgets to the screen. Unfortunately, their positions (relative to other widgets) changes when the tablet on which I am running the app is rotated. Now I have built a function that repositions them, and I would like to call this function when the tablet is rotated. How can I implement this?

My attempts so far...

I have seen from the Kivy documentation that the Window class has an on_rotate event, and have tried to incorporate this into my program in several different ways.

First, I tried implementing the callback after the if __name__ == '__main__' statement. Something like:

if __name__ == '__main__':
     app = MainApp()
     Window.on_rotate = lambda: app.reposition_widgets()
     app.run()

That did nothing. In vain I also tried:

if __name__ == '__main__':
     app = MainApp()
     Window.on_rotate(app.reposition_widgets)
     app.run()

I then attempted to bind the widgets to on_rotate events, something like:

class CustomWidget(Widget):
     def __init__(self, **kwargs)
          super().__init__(**kwargs)
          self.bind(on_rotate = self.reposition_widgets)

That did nothing. Neither did:

class CustomWidget(Widget):
     def __init__(self, **kwargs)
          super().__init__(**kwargs)
     
     on_rotate = reposition_widgets

My final attempt was to create a Window class in the accompanying kv file and the Python file, then specify the on_rotate event from there. Something like:

#kv file
Window:
     on_rotate: app.reposition_widgets()

That didn't work either.

Possible work around

  1. To be honest, rotating the screen is not all that useful for my app, and so it wouldn't be all that bad if I just disabled screen rotation. However, I was not able to find a good way of doing so in the documentation. Do you know how I would go about doing this?

  2. Binding the widgets to the on_pos event - or something similar. Something like:

class CustomWidget:
     
     def reposition_widgets():
         # Code here

     on_pos = reposition_widgets

The problem with this is that the widgets move about a lot, which means that the function gets called a lot - causing problems elsewhere.


Let me know if you would like to see more code. I have over 1000 lines spread over several files, and felt that just copy-and-pasting wouldn't be particularly useful.

jda5
  • 1,390
  • 5
  • 17
  • I never used kivy, but try `Window.on_rotate(app.reposition_widgets)` note the absence of parenthesis. You called `reposition_widgets` instead of passing it as a callback. – DeepSpace Nov 09 '20 at 16:40
  • Thanks for the suggestion! I've just tried what you've suggested and unfortunately it hasn't worked – jda5 Nov 09 '20 at 16:44
  • 1
    Check this [answer to a similar question](https://stackoverflow.com/questions/39430824/how-to-detect-screen-rotation-on-android-in-kivy). – John Anderson Nov 09 '20 at 19:34
  • That dupe looks promising, although it only has a hint at an answer. @JacobStrauss, If you get it working due to the dupe, you could self-answer, and then flag the original as a dupe to this one. – SiHa Nov 10 '20 at 11:36

1 Answers1

0

I was able to solve this issue using the on_size event.

class CustomWidget(Widget):
    
    def reposition_widgets(self):
        # Reposition logic here

    on_size = reposition_widgets

This worked quite well actually. I added an additional parameter in the reposition_widgets function to differentiate between when I was repositioning because of on_size and when I was repositioning because I was calling it (see example below). However, this is not always necessary.

class CustomWidget(Widget):
    
    def reposition_widgets(self, rotation=False):
        if rotation:
            # When function is called due to on_size
        else:
            # When function is called in code

    on_size = lambda self, *args: self.reposition_widgets(rotation=True)
jda5
  • 1,390
  • 5
  • 17