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.
Scripter - Pythonista UI animation framework built on ui.View.update()
-
Added fly_out effect with a direction option, see demo.
-
Syntax error in line 343
f' not supported in my Pythonistaf'strings' are a Python 3.6+ feature which is why they work in the Pythonista beta but not in the App Store version.
I saw a really cool module https://github.com/asottile/future-fstrings that allows all Pythons (even 2.7!!) to do f-strings just by adding:
# -*- coding: future_fstrings -*-
as the first or second line of the file. No import or anything. Not sure if it will work in Pythonista but pretty mindbending nevertheless. -
@ccc Thanks but I'll wait for next version...
-
With some more practical experience with this I decided to change the way effects are used, to remove the need to define any classes or functions just to use simple effects.
There’s also now some proper API docs.
From the Quick Start:
Quick start
In order to start using the animation effects, just import scripter and call the effects as functions:
from scripter import * hide(my_button)
Effects expect an active UI view as the first argument. This can well be
self
orsender
where applicable.If you want to create a more complex animation from the effects provided, combine them in a
script:@script def my_script(): move(my_button, 50, 200) pulse(my_button, 'red') yield hide(my_button)
Scripts control the order of execution with
yield
statements. Here movement and a red
pulsing highlight happen at the same time. After both actions are completed,my_button
fades
away.Run scripter.py in Pythonista to see a demo of most of the available effects.
-
And courtesy of iOS 11 screen recording, here’s a video of the demo.
-
Hmm...I must be doing something wrong. Tried to run scripter.py ( to see demo) but all I get is https://imgur.com/a/na0Nx
-
@ihf, I did not test on iPad, and
present
had a wrong argument.Either download the latest or change line 539 to:
v.present('full_screen')
-
@mikael Thanks that worked! (In the version I have, it was line 552).
-
@omz, is there a way to access the various timing options in
scene
Action
as a function of t? Would like to have the option of using those in Scripter. -
See https://github.com/controversial/ui2/blob/master/ui2/animate.py
The above is mainly for ui animation. You may look at scene_drawing.py code to see how various timing options are implemented.
-
@enceladus, thanks, your answer guided me on a hunt through UIKit and SceneKit docs. I could not find the easing functions conveniently exposed by Apple.
-
scene_drawing.py in modules/standard library 3.5/site-packages. You can use curve_sinodial, curve_ease_in like functions.
-
current_func = lambda s,t,d:s+curve_sinodial(t)*d should work (I am outside and I will post the proper working code later.)
-
@enceladus, thanks! Need to test this, but looks like all of the functions there are directly useable with Scripter.
-
So yes, you can use these with any of the
slide_x
scripts for example:import scene_drawing slide_value(view, 'y', 100, ease_func=scene_drawing.curve_bounce_out)
I could not find the functions documented anywhere, so here’s a reference:
-
Here is a simple demo example that I used for testing. I hope it is useful.
from scripter import * import ui import scene_drawing @script def custom_action(my_view): move(my_view, 200, 200) pulse(my_view, 'red') yield 1 hide(my_view) @script def custom_reverse_action(my_view): show(my_view) yield move(my_view, 100, 20) pulse(my_view, 'black') toggle = True def button_action(sender): global toggle s = sender.superview ease_func = scene_drawing.curve_sinodial #ease_func = scene_drawing.curve_ease_in #ease_func = scene_drawing.curve_ease_out #ease_func = scene_drawing.curve_ease_back_in #ease_func = scene_drawing.curve_ease_back_out l = s['label1'] title = sender.title if title == 'move': if toggle: move(l, 200, 200, ease_func=ease_func) else: move(l, 100,20, ease_func=ease_func) elif title == 'hide': if toggle: hide(l, ease_func=ease_func) else: show(l, ease_func=ease_func) elif title == 'rotate': if toggle: rotate(l, 30, ease_func=ease_func) else: rotate(l, 0, ease_func=ease_func) elif title == 'custom': if toggle: custom_action(l) else: custom_reverse_action(l) elif title == 'color': if toggle: slide_color(l, 'text_color', 'green') else: slide_color(l, 'text_color', 'black') elif title == 'count': if toggle: set_value(l, 'text', range(1,101), lambda c: f'count: {c}') else: set_value(l, 'text', range(100, 0, -1), lambda c: 'Text to be animated' if c == 1 else f'count: {c}') elif title == 'fly_out': if toggle: fly_out(l, 'down') else: move(l, 100, 20) elif title == 'font_sz': if toggle: slide_value(l, 'font', 40, start_value=20, map_func=lambda sz: ('Helvetica', sz) ) else: slide_value(l, 'font', 20, start_value=40, map_func=lambda sz: ('Helvetica', sz) ) toggle = not toggle v = ui.View(frame=(0,0,400,400)) l = ui.Label(text='Text to be animated', font=('Helvetica', 20), name='label1', frame=(100,20,200,100)) b1 = ui.Button(title='move', frame=(20, 300, 80,50), action=button_action) b2 = ui.Button(title='hide', frame=(120, 300, 80,50), action=button_action) b3 = ui.Button(title='rotate', frame=(220, 300, 80,50), action=button_action) b4 = ui.Button(title='custom', frame=(320, 300, 80,50), action=button_action) b5 = ui.Button(title='color', frame=(20, 350, 80,50), action=button_action) b6 = ui.Button(title='count', frame=(120, 350, 80,50), action=button_action) b7 = ui.Button(title='fly_out', frame=(220, 350, 80,50), action=button_action) b8 = ui.Button(title='font_sz', frame=(320, 350, 80,50), action=button_action) v.add_subview(l) v.add_subview(b1) v.add_subview(b2) v.add_subview(b3) v.add_subview(b4) v.add_subview(b5) v.add_subview(b6) v.add_subview(b7) v.add_subview(b8) v.present('sheet')
-
@enceladus, thanks again. Looks like something that I was thinking of doing, splitting out the demo from the main code, and having buttons to launch specific effects. Would you mind if I developed this further and included it in the repo?
-
Fell free to use whatever way you want. Anyway it is mostly your code.
-
@enceladus, in your
custom_action
, you are yielding 1 (second), which is not doing what it intuitively should, i.e. wait for 1 second after the previous actions have completed. Currently you need to have ayield
followed by theyield 1
.This confirms the misgivings I have had about the
yield wait
syntax. I would want it to work the way you used it. -
In the latest version
yield
now works as you would expect, i.e.:move(view, 100, 100) yield 2 pulse(view)
Also, scene_drawing easing functions are wrapped, so you can use them without separately importing them.