Joystick UIControl ui wrapper?
@mcriley821, also no need to navigate to btn and label in moveButton, the variables are already available (in the function’s closure).
@mcriley821, instead of:
btn.center = (btn.center.x + touchVec.x / 10, btn.center.y + touchVec.y / 10)
... you should be able to just say:
btn.center += touchVec / 10
... but for some reason it does not seem to exactly work.
@mcriley821, ui.View conveniently sets all its kwargs, so we can just call super() with them, no need to iterate manually. Also, defaults can be set before. tint_color we handle separately, as it is a custom property. (In general I would advice against overriding the ui.View properties, it will come back to haunt you.)
def __init__(self, tint_color='grey', **kwargs): kwargs.setdefault('background_color', 'black') super().__init__(**kwargs) ...
mcriley821 last edited by mcriley821
@mikael I iterate manually to catch a non-square frame. Is there a different way to make sure this happens? I feel like I also need to override the frame setter to catch it after init
@mcriley821, sorry, forgot to include that bit. Seems enough to check it after super(). If you want to enforce it continuously, layout() is a good option since, in addition frame, size can change via bounds, width and height.
def __init__(self, tint_color='grey', **kwargs): kwargs.setdefault('background_color', 'black') super().__init__(**kwargs) if self.frame.width != self.frame.height: raise ValueError('Joystick must be square') ...
@mcriley821, also makes sense to set self.stick.flex = 'WH', so that it will resize with its superview.
@mcriley821, taking the arithmetic capabilities of ui.Point/Vector2, the calculations can collapse to:
def touch_moved(self, touch): touch = touch.location radius_vector = [self.radius]*2 touch_vector = touch - radius_vector magnitude = abs(touch_vector) if magnitude < self.radius: self.stick.center = touch else: self.stick.center = ( touch_vector / magnitude * self.radius + radius_vector ) if self.action: self.action(self, touch_vector) return
Thank you for your patience, I think I am done.
mcriley821 last edited by
@mikael I really appreciate you taking the time to help me and the improvements! I’ve already updated a bunch of stuff from your suggestions and I’m currently working on using the ‘iob:pinpoint' ionicon to add a type of texture to the ‘joystick’!
@mcriley821, interesting! Careful placement to get just the head of the pin?
import ui import objc_util CAGradientLayer = objc_util.ObjCClass('CAGradientLayer') class ShadedCircle(ui.View): def __init__(self, color1='#ff8484', color2='red', **kwargs): super().__init__(**kwargs) o_color1 = objc_util.UIColor.colorWithRed_green_blue_alpha_( *ui.parse_color(color1)).CGColor() o_color2 = objc_util.UIColor.colorWithRed_green_blue_alpha_( *ui.parse_color(color2)).CGColor() layer = self.objc_instance.layer() grlayer = CAGradientLayer.layer() grlayer.setType('radial') grlayer.frame = layer.bounds() grlayer.setColors_([o_color1, o_color2]) layer.insertSublayer_atIndex_(grlayer, 0) grlayer.setStartPoint(objc_util.CGPoint(0.25, 0.25)) grlayer.setEndPoint(objc_util.CGPoint(1.0, 1.0)) grlayer.locations = [0.0, 1.0] def layout(self): self.height = self.width self.corner_radius = self.width / 2 if __name__ == '__main__': v = ui.View() c = ShadedCircle( center=v.bounds.center(), flex='RTBL', ) v.add_subview(c) v.present('fullscreen', animated=False)
mcriley821 last edited by
I just subclassed a ui.View object again and did some more stuff to check for changing the frame later with layout. Had to use layout or it wasn’t resizing correctly, or changing some of the attributes to make the stick/texture of the joystick not resize.
I decided to start a github repo for Pythonista and posted it in there.
DoinStuffMobile last edited by
@mcriley821 Wow, I clearly did not look hard enough initially! That's amazing!