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.


    Ui.TextView, detect if virtual keyboard is open/visible

    Pythonista
    5
    15
    4053
    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.
    • rownn
      rownn last edited by

      Hi everyone,

      I work on a scene with ui.TextView and I‘d like to know how I could detect if the virtual keyboard is open/visible or not. Depending on the visibility of the keyboard I‘d like to do some layout changes. Does somebody have a hint for me?

      Greetings :)
      rownn

      stephen cvp 4 Replies Last reply Reply Quote 0
      • stephen
        stephen @rownn last edited by

        This post is deleted!
        1 Reply Last reply Reply Quote 0
        • cvp
          cvp @rownn last edited by

          @rownn test this

          from objc_util import *
          import ui
          
          tv =ui.TextView()
          
          def x(sender):
          	resp = ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder()
          	tv.name = 'keyboard is visible = ' + str(resp == ObjCInstance(tv))
          
          b = ui.ButtonItem()
          b.title = 'test'
          b.action = x
          tv.right_button_items = (b,)
          tv.present() 
          
          1 Reply Last reply Reply Quote 2
          • cvp
            cvp @rownn last edited by cvp

            @rownn if you have multiple TextFields/ TextViews you could compare the first responder with ObjCInstance(all of them) to determine which one has the keyboard/cursor

            1 Reply Last reply Reply Quote 1
            • stephen
              stephen @rownn last edited by stephen

              @rownn i annotated with comments.

              
              class MyTextView(ui.TextView):
              	def __init__(self, *args, **kwargs):
              		self.delegate = self
              	
              	def begin_editing(self):
              		# forces keyboard to present
              		pass
              
              	def end_editing(self):
              		# forces keyboard to close
              		pass
              
              	def replace_range(self, range, text):
              		pass
              		
              	### start of delegate methods ###
              	
                  def TextView_should_begin_editing(self, textview):
                  	# resize and reposition for keyboard
                      return True
                      
                  def TextView_did_begin_editing(self, textview):
                  	# keyboard presented
                      pass
                      
                  def TextView_did_end_editing(self, textview):
                      pass
                      
                  def TextView_should_return(self, textview):
                      # resize and reposition for no keyboard
                      textfield.end_editing()
                      # keyboard not presented
                      return True
                      
                  def TextView_should_change(self, textview, range, replacement):
                      return True
                      
                  def TextView_did_change(self, textview):
                      pass
              
              
              1 Reply Last reply Reply Quote 2
              • stephen
                stephen last edited by

                @rownn to follow along @cvp if you have multiple TextViews you can use a separate object class with the methods and set that to the delegate for each and each will get their own so you wouldnt need to find out who is currently active

                
                class MyTextViewDelegate(object):
                    def TextView_should_begin_editing(self, textview):
                    	# resize and reposition for keyboard
                        return True
                        
                    def TextView_did_begin_editing(self, textview):
                    	# keyboard presented
                        pass
                        
                    def TextView_did_end_editing(self, textview):
                        pass
                        
                    def TextView_should_return(self, textview):
                        # resize and reposition for no keyboard
                        textfield.end_editing()
                        # keyboard not presented
                        return True
                        
                    def TextView_should_change(self, textview, range, replacement):
                        return True
                        
                    def TextView_did_change(self, textview):
                        pass
                
                
                1 Reply Last reply Reply Quote 1
                • stephen
                  stephen last edited by

                  @rownn both methoods should work. but if you want my opinion i would suggest usung @cvp 's objC route. i know mine works but i personally wish i learned objc_util when i was learning python. and this sounds like a perfect time to for yourself if you havnt already. you can even do my method using objc_util. using th UITextView if i recall correctly 🤓

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

                    Of course you can always hook into the keyboard frame change notifications by implementing custom view for your root.

                    https://forum.omz-software.com/topic/5189/moving-the-keyboard-input-text-view-to-be-visible/4

                    stephen 1 Reply Last reply Reply Quote 3
                    • stephen
                      stephen @JonB last edited by

                      @JonB i completely forgot about those methods Thank you 😎😅

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

                        Hi everyone,

                        my first idea was to detect if the TextView is focused or not, but sometimes I work with an external keyboard, so JonBs hint is perfect. It works perfectly fine for me. Hope there won‘t be any unexpected issues. Here the reduced code:

                        from scene import *
                        import ui
                        
                        class MyScene (Scene):
                        	def setup(self):
                        		v = V(scene=self)
                        		self.view.add_subview(v)
                        		
                        		background = Node(parent=self)
                        		background.position = (self.size.w/2,self.size.h/2)#(self.size.w/2, self.size.h/2)
                        		background.add_child(ShapeNode(ui.Path.rect(0,0,self.size.w,self.size.h), fill_color='#dddddd', stroke_color='clear'))
                        		
                        		self.add_child(background)
                        		
                        class V(ui.View):
                        	def __init__(self, *args, **kwargs):
                        		self.scene = kwargs["scene"]
                        		self.textView_H = 200
                        		self.frame=(0, self.scene.size.h-self.textView_H, self.scene.size.w, self.scene.size.h)
                        		
                        		self.tv=ui.TextView(frame=(10, 0, self.scene.size.w-20, self.textView_H), font=('Courier', 17.0), background_color='#333333', text_color = '#ffffff')
                        		self.tv.text = 'Heyhey.'
                        		self.tv.delegate=self
                        		self.add_subview(self.tv)
                        	
                        	def keyboard_frame_will_change(self, frame):
                        		self.animate(frame)
                        		
                        	def animate(self, frame):
                        		def animation():
                        			self.y = self.scene.size.h-self.textView_H-frame[3]
                        		ui.animate(animation, duration=0.25)
                        	
                        		
                        if __name__ == '__main__':
                        	run(MyScene(), PORTRAIT, show_fps=True)
                        

                        Thank you guys. Amazing fast replying forum!

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

                          The animation part of the code seems to be not needed.
                          So...

                          def keyboard_frame_will_change(self, frame):
                          	self.y = self.scene.size.h-self.textView_H-frame[3]
                          	#self.animate(frame)
                          		
                          #def animate(self, frame):
                          	#def animation():
                          	    #self.y = self.scene.size.h-self.textView_H-frame[3]
                          	#ui.animate(animation, duration=0.25)
                          	 ```
                          1 Reply Last reply Reply Quote 0
                          • stephen
                            stephen last edited by

                            @rownn what JonB gave shoudnt give any issues. this is made exactly for what you need. i personally forgot all about theme lol

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

                              Great! Thanks:)

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

                                @rownn, the keyboard reveal delegates used to have serious issues, at least on the iPhone.

                                If you tried to use the exact frame height values they were very confusing, probably not properly handling the safe area. And also the handlers kept running after your script was done.

                                Would be happy to hear if these issues have been resolved in the intervening years.

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

                                  Yes, also issues with landscape vs portrait vs upside-down, etc.

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