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
    4072
    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.
    • 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