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.
[Tip] ui.Rect, if you are not using it for ui you should
-
I am sure I have done this type of tip before. But as time passes on and new users join they get old. This is only for people who don't know about ui.Rect. There is a small problem with ui.Rect. It's not documented as a ui.Rect. It's actually documented as - class scene.Rect(x, y, w, h). Also the autocomplete in the editor does not recognise ui.Rect. Anyway ui.Rect and scene.Rect are the same. Regardless, ui.Rect is recognised by the interpreter.
So why is it important to know about it? Firstly , attrs in ui.View like frame and bounds are ui.Rects. They can be assigned a tuple or a ui.Rect, omz takes care of that. But it's the methods you can use on ui.Rects that makes it worth knowing about. It's not rocket science stuff, but can save you a lot of time and reduce bugs. There is a link to the documentation below. But it can really help reduce your code and simplify things.
I have posted below an example of adding variable height views to a scrollview. Maybe the code is not as tight as I could be, but you can see it's pretty simple. Granted, you can do the same thing doing the calls yourself, but there is a lot of help built in already.
Again, this is only useful if you are unaware of ui.Rect/scene.Rect
Hope it's useful for someone
The sample code below should be size and orientation friendly
# Pythonista Forum - @Phuket2 import ui, editor class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.sv = None self.v_gap = 10 # vertical space between views self.make_view() def make_view(self): sv = ui.ScrollView(frame = self.bounds.inset(20, 20)) sv.flex = 'wh' sv.bg_color = 'white' sv.corner_radius = 3 self.sv = sv self.add_subview(sv) def add_view(self, h): parent = self.sv # our parent is the ScrollView r = ui.Rect(0, 0, parent.width, h).inset(5, 5) v = ui.View(frame = r) v.y = self.calc_y() v.border_width = 1 v.corner_radius = 6 v.flex = 'w' parent.add_subview(v) parent.content_size = (0, v.frame.max_y + self.v_gap ) def calc_y(self): # returns the new y for the next element that will be added to # scrollview. # seems stupid to do this. i am tending more to do this style # now. have a var that points to our parent contextually. # i make less mistakes this way, and think faster parent = self.sv # our parent is the ScrollView if not len(parent.subviews): return self.v_gap return parent.subviews[len(parent.subviews)-1].frame.max_y + self.v_gap if __name__ == '__main__': _use_theme = True w, h = 600, 800 w, h = 320, 568 # iphone 5 up f = (0, 0, w, h) style = 'sheet' animated = False mc = MyClass(frame=f, bg_color='white', name = 'ScrollView Test') if not _use_theme: mc.present(style=style, animated=animated) else: editor.present_themed(mc, theme_name='Oceanic', style=style, animated=animated) # its just an example... we do the call to create the scrollview # views here. h_list = [100, 200, 50, 100, 60, 80, 90, 300, 44, 60, 90, 300, 90] for h in h_list: mc.add_view(h)
-
I have been working on a list of items where only one is selectable as in radio buttons in another script. But I come up with something that I think is ok. Was easily to add to this code. And that's somehow the point in my mind.
# Pythonista Forum - @Phuket2 import ui, editor class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.sv = None self.v_gap = 10 # vertical space between views self.make_view() def make_view(self): sv = ui.ScrollView(frame = self.bounds.inset(20, 20)) sv.flex = 'wh' sv.bg_color = 'white' sv.corner_radius = 3 self.sv = sv self.add_subview(sv) def add_view(self, h): parent = self.sv # our parent is the ScrollView r = ui.Rect(0, 0, parent.width, h).inset(5, 5) v = ui.View(frame = r) v.y = self.calc_y() v.border_width = 1 v.corner_radius = 6 v.flex = 'w' parent.add_subview(v) # added this r = ui.Rect(0, 0, v.height, v.height).inset(10, 10) btn = ui.Button(name = 'btn', frame = r) btn.choice = False # dynamically added attr btn.image = ui.Image.named('iob:ios7_checkmark_outline_256') btn.tint_color = 'lightgray' btn.action = self.action v.add_subview(btn) parent.content_size = (0, v.frame.max_y + self.v_gap ) def calc_y(self): # returns the new y for the next element that will be added to # scrollview. # seems stupid to do this. i am tending more to do this style # now. have a var that points to our parent contextually. # i make less mistakes this way, and think faster parent = self.sv # our parent is the ScrollView if not len(parent.subviews): return self.v_gap return parent.subviews[len(parent.subviews)-1].frame.max_y + self.v_gap def action(self, sender): # added this # the action for the button parent = self.sv # our parent is the ScrollView for v in parent.subviews: btn = v['btn'] btn.tint_color = 'lightgray' btn.choice = False sender.tint_color = 'deeppink' sender.choice = True if __name__ == '__main__': _use_theme = True w, h = 600, 800 w, h = 320, 568 # iphone 5 up f = (0, 0, w, h) style = '' animated = False mc = MyClass(frame=f, bg_color='white', name = 'ScrollView Test') if not _use_theme: mc.present(style=style, animated=animated) else: editor.present_themed(mc, theme_name='Oceanic', style=style, animated=animated) # its just an example... we do the call to create the scrollview # views here. #h_list = [80, 80, 80, 80, 60, 80, 90, 300, 44, 60, 90, 300, 90] h_list = [80] * 20 for h in h_list: mc.add_view(h)
-
thank you very much for sharing this @Phuket2 , i am trying to put up some interface and this hepls a lot. Btw, super().whatever(blabla) generates an error for e, i had to replace it by ui.View.whatever(self, blabla) and then it works.
Thanks
-
@jmv38 , glad it helps. The super() call is python 3, so I guess you are on on the Pythonista 2.x app. Super is nice as you don't have to specify the parent implicitly by name. But anyway, it's python 3 only.
I have been working on the below a little today. (Many friends turned up tonight, so things went a little south).
Again about making a view. I fixed a issue I had before when dealing with margins. It's still not 100% in my mind. I need to put some more thought into the top and bottom margins. I know how to adjust them, it's just how it to it the right way, if at all. Anyway, i feel this is more flexible as it just returns a list of ui.Rects.
# Pythonista Forum - @Phuket2 import ui, editor def make_view_rects(view, v_list, vert=True, abs_size=True, margin=(0, 0)): # return a list of ui.Rects r = ui.Rect(*view.bounds) def translate_number(wh, n): if n == 0 or n > 1: return n return wh if n == -1 else wh * n # adjust v_list to account for margins, if we want positive numbers # to remain a fixed size, i.e if you pass 44, and a margin, it will # remain 44 if abs_size: extra = margin[0] * 2 if vert else margin[1] * 2 v_list = [x if x == 0 else (x + extra) for x in v_list] # translate the numbers in v_list to absolute numbers, except zero v_list = [translate_number((r.height if vert else r.width), x) if x else x for x in v_list] zero_count = v_list.count(0) # aviod divide by zero error var = ((r.height if vert else r.width) - sum(v_list)) / zero_count\ if zero_count else ((r.height if vert else r.width) - sum(v_list)) # replaces 0 in v_list with var. v_list = [var if x == 0 else x for x in v_list] lst = [] # a list of the rects created, we return this xy = 0 # keep track of width or height for num in v_list: lst.append(ui.Rect(0, xy, r.width, num).inset(*margin) if vert else ui.Rect(xy, 0, num, r.height).inset(*margin)) xy += num return lst class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.question_panel = None self.responses_panel = None self.toolbar_panel = None self.make_view() def make_view(self): inset_w = 10 inset_h = 10 v_rects = make_view_rects(self, [60, 0, 0, 0, 60], abs_size=True, vert=True, margin=(inset_h, inset_w)) for r in v_rects: v = ui.View(frame=r, bg_color='cornflowerblue') v.border_width = .5 v.corner_radius = 6 v.flex = 'tlwhbr' self.add_subview(v) if __name__ == '__main__': _use_theme = True w, h = 600, 800 w, h = 375, 667 f = (0, 0, w, h) style = 'sheet' mc = MyClass(frame=f, bg_color='white') if not _use_theme: mc.present(style=style, animated=False) else: editor.present_themed(mc, theme_name='Oceanic', style=style, animated=False)
-
to @jmv38...How, specifically in code, did you replace super() in @Phuket2 code, to get this to work in Pythonista 2.x.
-
@coomlata1 , if you replace the super line with
ui.View.__init__(self, *args, **kwargs)
I think there are a few variations, but this is what I used when I was on python 2.7x
The code posted are pretty simple examples. But when you are inheriting from different classes and experimenting a lot, super is really great because you don't have to refer to the base class like you do in py2 way. So chopping and refactoring your code is a lot easier. It eaves me a lot of fiddling around. If it didn't I would would use the older style to keep it py2 compatible
-
@ccc or anyone else, any remarks or suggesting to tighten up the make_view_rects function. I really like it. And I think that it only returns Rects rancher than creating views it's self is more appealing.
There are 2 issues I can see. One is the view param. This is a leftover, a ui.Rect should be passed in stead of the view. The other is that the margins give the right distance between the items. But if vert=True, the top and bottom margin is / 2. same goes when you go horizontally. I am not sure the result is entirely incorrect. I think more often than not you would want that result.
Anyway, happy to listen to any feed back if anyone has some.