omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Keyboard frame change view methods oddness...

    Pythonista
    textfield keyboard textview
    3
    12
    6243
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • shinyformica
      shinyformica last edited by shinyformica

      While implementing a system to determine which text input widget has focus, and place it in the right location when the keyboard shows up, I have found some odd and inconsistent behavior in the calling of the ui.View keyboard_frame_will_change() and keyboard_frame_did_change() methods. I'm curious if anyone else is seeing anything like this?

      First, it seems like they get called much more often than I'd expect when the keyboard shows up or hides or changes size. I was expecting a call to "keyboard_frame_will_change()" just before the keyboard shows or changes size, and then a call to "keyboard_frame_did_change()" just after it has finished showing or changing size.

      Instead, I see at least two calls to "will change" and then two calls to "did change" all with the same keyboard frame on my iPad, but on my iPhone 7, I'm seeing even more: two "will change" calls with one frame size, then two "did change" with that same size, then another set of two calls each to "will change" and "did change" with a somewhat different size, then another set of two calls each to "will change" and "did change" back to the first frame size.

      Also, on my iPhone, but not on the iPad, I see when I run my app in one orientation and then rotate to the other (so, from portrait to landscape or vice versa) and then tap a text field and bring up a keyboard, the reported frame size is either for the wrong orientation, or is invalid (0,0,0,0).

      Below I'm including the debugging output I get if I just print the "frame" parameter that "keyboard_frame_will_change()" and "keyboard_frame_did_change()" are given. For each it's just a single tap in a textfield, and the keyboard coming up:

      iPad, landscape orientation:
      keyboard frame will change: (0.00, 370.00, 1024.00, 398.00)
      keyboard frame will change: (0.00, 370.00, 1024.00, 398.00)
      keyboard frame did change: (0.00, 370.00, 1024.00, 398.00)
      keyboard frame did change: (0.00, 370.00, 1024.00, 398.00)
      
      iPad, portrait orientation:
      keyboard frame will change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame will change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame will change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame will change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame did change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame did change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame did change: (0.00, 711.00, 768.00, 313.00)
      keyboard frame did change: (0.00, 711.00, 768.00, 313.00)
      
      iPhone, portrait orientation:
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame will change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame did change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame did change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      
      iPhone, landscape orientation:
      keyboard frame will change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame will change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame will change: (0.00, 213.00, 667.00, 162.00)
      keyboard frame will change: (0.00, 213.00, 667.00, 162.00)
      keyboard frame did change: (0.00, 213.00, 667.00, 162.00)
      keyboard frame did change: (0.00, 213.00, 667.00, 162.00)
      keyboard frame will change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame will change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 667.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 667.00, 194.00)
      
      iPhone orientation change (Portrait to Landscape):
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame will change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame did change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame did change: (0.00, 451.00, 375.00, 216.00)
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame did change: (0.00, 409.00, 375.00, 258.00)
      keyboard frame will change: (0.00, 0.00, 0.00, 0.00)
      keyboard frame will change: (0.00, 0.00, 0.00, 0.00)
      keyboard frame did change: (0.00, 0.00, 0.00, 0.00)
      keyboard frame did change: (0.00, 0.00, 0.00, 0.00)
      keyboard frame will change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame will change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame will change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame will change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 375.00, 194.00)
      keyboard frame did change: (0.00, 181.00, 375.00, 194.00)
      

      For all the above, this is python2.7, and the iPad is running iOS 11.4.1 and the iPhone is running 12.0.1

      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by

        See https://forum.omz-software.com/topic/2701/keyboard-hiding-textview/8

        It used to be these methods were all wonky, and didn't use orientation properly. It has been a while since I tested this stuff, but I had a replacement method that fixed some of the errors. I think my fixes don't work anymore, but possibly this thread might spark some ideas.

        https://forum.omz-software.com/topic/2701/keyboard-hiding-textview/8

        1 Reply Last reply Reply Quote 0
        • shinyformica
          shinyformica last edited by

          @JonB well, I guess these issues still exist. Honestly, the situations where this is an actual problem are relatively unlikely to occur in the real-world use of my app, especially when I just ignore the repeated calls by comparing stored state and discarding superfluous ones.

          It's good to know that it isn't something I'm doing wrong, and I'll just hope that the next release of Pythonista fixes the issue. Thanks for the info, though!

          mikael 1 Reply Last reply Reply Quote 0
          • mikael
            mikael @shinyformica last edited by

            @shinyformica, reminder: the keyboard change events keep firing after your script ends, so be sure to check ui.on_screen before doing anything.

            1 Reply Last reply Reply Quote 0
            • shinyformica
              shinyformica last edited by

              So now that I'm a little less timid about reaching into objc when necessary...looks like if I just register to be notified of the:

              UIKeyboardWillChangeFrameNotification
              UIKeyboardDidChangeFrameNotification

              they are delivered in a much more reliable fashion than the window change methods available in ui.View. You get a single pair of notifications for each change in keyboard size, which means as long as you know which widget is receiving keyboard input, you can easily place it at the right location with a nice ui.animate().

              Seems to work reliably.

              @mikael I am definitely tracking whether my app is active or not, but important safety tip there.

              1 Reply Last reply Reply Quote 0
              • JonB
                JonB last edited by

                I am only seeing one keyboard_did_change call -- however if you run multiple views, or run a a script multiple times, you can seem to get multiple call backs.

                The bug seems to be related to how the view is first presented -- it is right when first presented, but after rotation it is wrong.

                I started writing up a UINotifocationCenter approach. Seems to be reliable. The trick is you need to make sure you unregister your observer when the python object is deleted -- I'm playing around with some ideas that uses a "canary" object and a weakref.finalize-r to deregister observers in a more robust manner..

                1 Reply Last reply Reply Quote 0
                • JonB
                  JonB last edited by

                  By the way, you might also consider using

                  UITextViewTextDidBeginEditingNotification
                  UITextFieldTextDidBeginEditingNotification

                  in leui of delegates to keep track of which control asked for the keyboard.

                  I'm not sure which order these get called, but you can use objc_setAssociatedObject(app, ns('currentTextField'), current_textfield_objcinstance, 0) to basically store the current field at the UIApplication.sharedApplication() level, making it easy to retrieve whenever. You could also store the kb frame in a similar way, to allow a working get_keyboard_frame method.

                  1 Reply Last reply Reply Quote 0
                  • shinyformica
                    shinyformica last edited by

                    @JonB yep, I traced it to the multiple-run issue as well...which meant my unregister wasn't properly happening either. I've gotten that mostly fixed, but I still actually prefer the NSNotificationCenter way of receiving keyboard change notifications better...since it's more app-global, and not view-specific.

                    I am using UITextViewTextDidBeginEditingNotification, UITextFieldTextDidBeginEditingNotification, etc. to track which widget is the active one, that seems to be really the only way...without iterating over views to find the firstResponder view. What I have now works quite well, but I need to make the unregistering part more robust.

                    1 Reply Last reply Reply Quote 0
                    • shinyformica
                      shinyformica last edited by shinyformica

                      Actually, to be clear, it seems like the multiple-keyboard-change call thing was not simply multiple-run, but also having multiple views which implement those methods. The combination made it so more than one view would end up fiddling with global state, using the plain notifications and a single receiver for them, I am guaranteed single notification.

                      mikael 1 Reply Last reply Reply Quote 0
                      • mikael
                        mikael @shinyformica last edited by

                        @shinyformica, would be much appreciated if you package this up as something reusable. The lack of reliable keyboard size notifications has always been a pain.

                        1 Reply Last reply Reply Quote 1
                        • shinyformica
                          shinyformica last edited by

                          @mikael yes, I think it would be good to package it. Or at least post template code for how to do it. I'll do that when I get a moment to this thread. What do we normally use to put up reusable code snippets? Is it this Gist thing I keep seeing?

                          mikael 1 Reply Last reply Reply Quote 0
                          • mikael
                            mikael @shinyformica last edited by

                            @shinyformica, gist seems good if it is clear that it is not going to need many revisions, issues, a Readme or collaboration. Otherwise, a git repo is not that much more work.

                            1 Reply Last reply Reply Quote 1
                            • First post
                              Last post
                            Powered by NodeBB Forums | Contributors