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
-
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 -
This post is deleted! -
@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()
-
@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
-
@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
-
@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
-
@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 learnedobjc_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 thUITextView
if i recall correctly π€ -
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
-
@JonB i completely forgot about those methods Thank you ππ
-
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!
-
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) ```
-
@rownn what JonB gave shoudnt give any issues. this is made exactly for what you need. i personally forgot all about theme lol
-
Great! Thanks:)
-
@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.
-
Yes, also issues with landscape vs portrait vs upside-down, etc.