Forum Archive

Ui woes

JonB

Been doing some heavy UI work, and Here are a few quirks/bugs I've found:

1) keyboard_get_frame and associated methods don't work in fullscreen, except in portrait, and only the view was started in portrait. In landscape, or if device is rotated, we get bad values.

Here is a sequence dumping out keyboard frame starting in portrait, and rotating clockwise

start portrait
kb frame ... = (0.0, 760.0, 768.0, 264.0)  correct
kb frame ... = (416.0, 0.0, 352.0, 1024.0) maybe correct if x,y,w,h are really y,x,h,w
kb frame ... = (0.0, 0.0, 768.0, 264.0). Incorrect y
kb frame ... = (0.0, 0.0, 352.0, 1024.0) also incorrect
kb frame ... = (0.0, 760.0, 768.0, 264.0) correct again, original orientation

Next, I restarted in landscape, and repeated the test

start in landscape
kb frame ... = (416.0, 0.0, 352.0, 768.0) hmmm. That's not right, should be 1024 width
kb frame ... = (0.0, 0.0, 768.0, 264.0) nope...y is wrong 
kb frame ... = (0.0, 0.0, 352.0, 768.0). Still wrong
kb frame ... = (0.0, 760.0, 768.0, 8.0).  Nope
kb frame ... = (416.0, 0.0, 352.0, 768.0)

Things seem to work ok in sheet, panel, etc. but,

2) in sheet view, the view's frame property lies about the x,y position. I guess this is because the view cannot be repositioned, however, it makes it tricky to figure out where the keyboard frame is relative to the view.

3) callbacks like keyboard_frame_will_change continue to be called even after the view is closed. I'm not sure if this is a desirable situation, it can lead to funny situations that require restart ( an exception in the will change function ends up in and endless cycle that can't be fixed by going back to console, etc.

4) changing a views size within draw() can cause strange problems. Like it seems the drawing context is set to original bounds. The issue is that, since measure_string can only be called from within draw(), if I want to resize the view to hold the string, there is no way to do it.

dgelessus

Try using ui.convert_point and ui.convert_rect. Both functions take a point/rect tuple and two views as arguments, and will translate the point/rect's coordinates from the first view's system into the second view's system. Setting None as one of the views will convert from/to absolute screen coordinates, so you might want to run ui.convert_rect(ui.get_keyboard_frame(), None, your_view) to get correct relative coordinates.

JonB

Thanks, that solves item 2, as it should let me get the keyboard relative to a sheet.

But in fullscreen, the keyboard frame returns garbage!

dgelessus

When are you checking the keyboard frame? You may have to wait a second or two after selecting the text field, otherwise you may be measuring the keyboard while the sliding animation is still happening. If you're using iOS 8, the keyboard size may also vary because of the word preditction bar above the keyboard.

JonB

I am using the argument to keyboard_frame_did_change, which seems to trigger after the animation is complete. The will and the did change method always get the same argument, only get_keyboard_frame is subject to a delay.... I have done experiments using delays, and the result is the same. See below. When running fullScreen landscape, this always reports a height of 1024, instead of width of 1024. The top box shows the delayed version, the second shows the frame passed to the did change method.

Otherwise works perfectly in panel, sheet,etc


import ui        

class testkb(ui.View):
    def __init__(self):
        self.bg_color=(1,1,0)
        self.t1=ui.Label(frame=(0,0,400,20))
        self.t2=ui.Label(frame=(0,30,400,20))
        self.t3=ui.Label(frame=(0,60,400,20))
        self.t4=ui.Label(frame=(0,90,400,20))
        self.t5=ui.TextView(frame=(0,120,400,20))
        [self.add_subview(s) for s in [self.t1,self.t2,self.t3,self.t4,self.t5]]
        self.t5.begin_editing()
    def keyboard_frame_did_change(self,frame):
        if self.on_screen:
            self.t2.text='kb frame ... = {0:3}'.format(frame)
            self.t3.text='frame = {0:3}'.format(self.frame)
            self.t4.text='biunds = {0:3}'.format(self.bounds)
            ui.delay(self.update_frame,3.0)
    def update_frame(self):
        self.t1.text='delayed ={0:3}'.format(ui.get_keyboard_frame())
            #print self.t1.text
T=test()
T.present('fullscreen')
dgelessus

'kay, I didn't even know that the keyboard_frame_did_change method is a thing. Thanks for telling me.