I'm doing a project with ui and objc_util (typical). I'm getting this strange behavior when overriding a ui.TextView's gestures; the gesture's view is somehow re-overriding the gestures.
The simplest code example I can muster is as follows:
from objc_util import *
import ui
UITap = ObjCClass("UITapGestureRecognizer")
class Node (ui.View):
class TextViewDelegate (object):
def textview_did_change(self, tv):
if '\n' == tv.text[-1]:
tv.text = tv.text[:-1]
tv.end_editing()
def __init__(self, *args, **kwargs):
ui.View.__init__(self, *args, **kwargs)
self.frame = (0, 0, *(ui.get_screen_size()))
tv = ui.TextView(
name="node_label",
frame=(100, 100, 50, 50),
bg_color="blue",
delegate=self.TextViewDelegate()
)
# this is where the interesting bit starts
tvObj = tv.objc_instance
# remove all the gestures of tv
for gesture in tvObj.gestureRecognizers():
tvObj.removeGestureRecognizer_(gesture)
# for a new gesture, we need a target and action
# how to make self a target? not really sure
# maybe making a "blank" target with the method
# would be enough? since self carries?
# I tried making a target of self, but crashes
target = create_objc_class(
"self",
methods=[self.handleTap_]
).alloc().init()
# now we have a target and action
# let's make the actual gesture
doubletap = UITap.alloc().initWithTarget_action_(
target,
"handleTap:"
)
# make into an actual doubletap, and add to view
doubletap.setNumberOfTapsRequired_(2)
tvObj.addGestureRecognizer_(doubletap)
# add the tv subview with a single gesture: doubletap
# can confirm only one gesture by uncommenting below
#print(self.objc_instance.gestureRecognizers()) # None
#print(tvObj.gestureRecognizers()) # doubletap
self.add_subview(tv)
# Now, without @static_method, everything is fine up until
# the below function is called -> results in TypeError of passing
# 4 args to a 3 arg function, since the first arg is self. However,
# with @static_method, we have to do some round-about trickery
# to do what we want.
@static_method
def handleTap_(_slf, _cmd, _gesture):
gesture = ObjCInstance(_gesture)
view = gesture.view()
# More interesting stuff happens now. On the first call of handleTap_,
# the next line prints only doubletap. On next calls, all the gestures
# have been reset
print(view.gestureRecognizers())
# we can only start editing now by becoming the first responder,
# since we can't access self
view.becomeFirstResponder()
# I assume here that the call to becomeFirstResponder instantiates
# a new TextView object somehow, yet this new object still contains
# a doubletap gesture. Re-tapping the TextView in the UI will start
# editing - no double tapping needed.
if __name__ == "__main__":
w, h = ui.get_screen_size()
view = Node(bg_color="white")
view.present()
What can I do to make self my target? Or how can I pass self to my method? Can I create a wrapper for the @static_method wrapper and pass self still? I'm stuck on what to do, since any direction I go seems to be a dead-end:
- make
selfinto a target = crash @static_method= no reference to the trueselfinstance- no
@static_method= TypeError - can't use global variables, since I hope to have ~10 of these
Nodesat a time
Also, I'd prefer to not use a TextField since they have that awful bounding box. I also think this issue would carry to a TextField anyhow.
Any ideas are greatly appreciated! I'm stumped!