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.
[Share] A skeleton for making and testing variable height cells for a ScrollView
-
i was not careful with how i handled cleared globals. change the setup_tableview_swizzle() to setup_tableview_swizzle(1), should do it.
With a little polish, I don't see why some objc in the background isn't a good long term solution. but pure python solution may also be more flexible (like your virtualcell class) -
@JonB , I did the change. I updated as you said. I got the same result
-
I updated
https://github.com/jsbain/objc_hacks/blob/master/tableview_rowheight.py
and
https://github.com/jsbain/objc_hacks/blob/master/rowheight_example.pyor, in stash just use
git clone https://github.com/jsbain/objc_hacks.git obj_hacks
, in which case you can get updates by cd obj_hacks, then git pull. Then run the rowheight_example script.
I need to handle swizzling in the presence of global clearing. What happens is even though the swizzled method implementation has been retained, its dependencies in the closure are not. I probably need to write the callback to import everything it needs in the def rather than in the module -- or, I need to ensure that dependencies get added to the pythonista_startup module so they don't get cleared.
-
@JonB l sorry to be a pain. But still does not work. Exactly same as last time. I am definitely using the right version. I used the stash cmd and cloned your git directory. I also restarted Pythonista. Running in 3.5 and have the latest beta from test flight. I tried running from both files.
I get a very strange artifact on the first line. It's been there from the first version I tried. In the pic below, the screen shot is with me pulling down the list so you can see it clearly. Not sure if this is a clue or not. But of course should not be there.
-
At a loss here... did you restart pythonista after installing the new script? I am about to upload a new one, which will catch errors and print out if an error is caught. maybe try in pythonista2 as well? It works for me in both betas though. I tried turning off animations as you do, and that works as well, so I am at a loss.... try this new version of tableview_rowheight and see if it spits out errors.
it should look like this
-
@JonB , hmmmm. Tried the new version. Same Same and not different. I did all you say like restart Pythonista etc. I have even restarted my ipad. I also tried running under 2.7 in the beta 3 app and running in the beta 2.7 app. Each time I see the same result. Also NO errors printed to the console. I seen your error catching statements in the last version. I get exactly the same as the previous pic I posted. Only one caveat to what I said before. I thought I was on the latest 3.x beta. I was not. It had failed to install yesterday. I didn't realise. I can't update it at the moment. There seems to be a global problem with some apple services. I think that's why I can't update right now. But I am only one behind. I will update as soon as I can. Again, I have been trying. Seems weird. You wouldn't think it was a hardware issue. Well, I would think so.
I also tried it (only py 2.7 beta) without disabling the animations in the pythonista_startup , with a forced restart of course. Same result.
I wish I could be more help. -
@Phuket2 If you interested in getting to the bottom of this, lets move the discussion over here
https://github.com/jsbain/objc_hacks/issues/5
I have a set of tests for you to run to help get to the bottom of what is happening... -
@JonB , thanks will do.
-
Just to anyone that had been looking at this thread @JonB resolved the issue I was having with his code ousted here to sizzle. He also mentions in a seperate post. Issues to do with different size data types returned for 32bit and 64bit devices. Anyway it's fixed now. The code is at his git hub repository listed above.
@JonB, thanks for your perseverance. I guess some good info come out of it. -
@JonB , sorry I hope you are ok I come back here now you solved the problem.
I have been sided tracked as usual. Trying to learn everything and learning nothing 😱
Ok, to the point.
I just cut up your example to represent how I would like to use the variable height cells. So far ok. It looks very promising. Meaning that getting all the smarts from ui.TableView.At least in my mind to get this to work the way I think it should work, I had to create a parallel list to store the cells heights to be sure I recover it correctly when your swizzled callback is called.
The reason for my post is maybe I am missing something easy, and can recover the height in a more simple way rather than creating the list.
The other thing is you say:
t_o=objc_util.ObjCInstance(t) t_o.estimatedRowHeight=44
Is optional. It does not appear it is. Without this seems to create all the cells at once rather than requesting as they come into view. Also crashes without that code.
#!python3 import ui from random import randint def make_cell(): cell = ui.TableViewCell() h = randint(44, 90) cell.height = h cell.text_label.text = 'cell height - ' + str(h) return cell class MyTableViewDataSource (object): def __init__(self): self.row_heights = None def tableview_number_of_sections(self, tableview): # Return the number of sections (defaults to 1) return 1 def tableview_number_of_rows(self, tableview, section): # Return the number of rows in the section num_rows = 500 if not self.row_heights: self.row_heights = [44] * num_rows return num_rows def tableview_cell_for_row(self, tableview, section, row): # Create and return a cell for the given section/row cell = make_cell() self.row_heights[row] = cell.height return cell print('in get cell', str(row)) cell = ui.TableViewCell() cell.text_label.text = 'Foo Bar' return cell def tableview_title_for_header(self, tableview, section): # Return a title for the given section. # If this is not implemented, no section headers will be shown. return 'Some Section' def tableview_can_delete(self, tableview, section, row): # Return True if the user should be able to delete the given row. return True def tableview_can_move(self, tableview, section, row): # Return True if a reordering control should be shown for the given row (in editing mode). return True def tableview_delete(self, tableview, section, row): # Called when the user confirms deletion of the given row. pass def tableview_move_row(self, tableview, from_section, from_row, to_section, to_row): # Called when the user moves a row with the reordering control (in editing mode). pass def tableview_height_for_section_row(self, tv,section,row): print('height -', str(self.row_heights[row])) return self.row_heights[row] #return 10+(row/5)**2 if row<50 else 10+((100-row)/5)**2 import tableview_rowheight, ui, objc_util # create a tableview and delegate and datasource, per usual #tableview_rowheight.setup_tableview_swizzle(False) t=ui.TableView(frame=(0,0,200,576)) d= MyTableViewDataSource() #ui.ListDataSource([str(x) for x in range(100)]) t.data_source=t.delegate=d # here i will just create height that grows then shrinks again #def tableview_height_for_section_row(tv,section,row): #return 10+(row/5)**2 if row<50 else 10+((100-row)/5)**2 #d.tableview_height_for_section_row=tableview_height_for_section_row # this is optional, but speeds up initial display and scrolling # set to nominal or average height t_o=objc_util.ObjCInstance(t) t_o.estimatedRowHeight=44 t.present('sheet')
-
-
The trick would be getting AutoLayout to work via objc_util. I have seen various autoLayout properties, but have not tried getting them to work.
-
@JonB where have you seen auto layout properties?
Anyway if we can get this to work it seems quite promising and not much code either! (Hopefully)
I know how to set the estimated row height. When I tried the
UITableViewAutomaticDimension
...first of all, I don't know what that is!!! Or how to get it! -
UIViews have a autoresizingMask property, and an addConstraint() method, together these define autolayout, I think. @Webmaster4o, this would be a good addition to ui2, as it gives more powerful layout.
autoresizingMask takes an integer bitmask, which you add up the options you want:
UIViewAutoresizingNone = 0 UIViewAutoresizingFlexibleLeftMargin = 1 << 0 UIViewAutoresizingFlexibleWidth = 1 << 1 UIViewAutoresizingFlexibleRightMargin = 1 << 2 UIViewAutoresizingFlexibleTopMargin = 1 << 3 UIViewAutoresizingFlexibleHeight = 1 << 4 UIViewAutoresizingFlexibleBottomMargin = 1 << 5 ObjCInstance(v).autoresizeMask=UIViewAutoResizingFlexibleWidth+UIViewAutoResizingWidth
it should be possible to apply these to tableviewcells, and to the tableview itself..
UITableViewAutomaticDimension is -1.0, you set the rowheight to this value.
-
@jonb ...hmm... This is way over my head. I've tried this but it doesn't work.
import ui from objc_util import * class TableData(object): def __init__(self): self.data = [{'value': str(i), 'height': i+40} for i in range(10)] def tableview_number_of_rows(self, tableview, section): return len(self.data) def tableview_cell_for_row(self, tableview, section, row): cell = ui.TableViewCell() label = ui.Label() label.text = self.data[row]['value'] label.number_of_lines = 0 label_objc = ObjCInstance(label) UIViewAutoresizingFlexibleTopMargin = 1 << 5 UIViewAutoresizingFlexibleBottomMargin = 1 << 5 UIViewAutoresizingFlexibleHeight = 1 << 5 UIViewAutoresizingFlexibleLeftMargin = 1 << 5 label_objc.autoresizeMask = UIViewAutoresizingFlexibleTopMargin + UIViewAutoresizingFlexibleBottomMargin + UIViewAutoresizingFlexibleHeight + UIViewAutoresizingFlexibleLeftMargin label.height = self.data[row]['height'] cell.content_view.add_subview(label) return cell tv = ui.TableView() tv.data_source = TableData() tv_objc = ObjCInstance(tv) tv_objc.rowHeight = -1.0 #UITableViewAutomaticDimension tv_objc.estimatedRowHeight = 40.0 tv.present()
... Scratching my head :)
-
-
@ccc ... I have no clue what flipping bits do! :)
But even if I apparently flip the bits differently I don't get any bit closer !
I'm in deep water...drowning...and the objc piranhas are coming.
Adjusted code ..maybe a step closer ...(?):
import ui from objc_util import * class TableData(object): def __init__(self): self.data = [{'value': str(i), 'height': i+40} for i in range(10)] def tableview_number_of_rows(self, tableview, section): return len(self.data) def tableview_cell_for_row(self, tableview, section, row): cell = ui.TableViewCell() label = ui.Label() label.text = self.data[row]['value'] label.number_of_lines = 0 label_objc = ObjCInstance(label) UIViewAutoresizingNone = 0 UIViewAutoresizingFlexibleLeftMargin = 1 << 0 UIViewAutoresizingFlexibleWidth = 1 << 1 UIViewAutoresizingFlexibleRightMargin = 1 << 2 UIViewAutoresizingFlexibleTopMargin = 1 << 3 UIViewAutoresizingFlexibleHeight = 1 << 4 UIViewAutoresizingFlexibleBottomMargin = 1 << 5 label_objc.autoresizeMask = UIViewAutoresizingFlexibleWidth + UIViewAutoresizingFlexibleTopMargin + UIViewAutoresizingFlexibleBottomMargin + UIViewAutoresizingFlexibleHeight label.height = self.data[row]['height'] cell.content_view.add_subview(label) return cell tv = ui.TableView() tv.data_source = TableData() tv_objc = ObjCInstance(tv) tv_objc.rowHeight = -1.0 #UITableViewAutomaticDimension tv_objc.estimatedRowHeight = 40.0 tv.present()
-
Turns out the textlabel already has constraints built in, so all you have to do is:
set number_of_lines=0
set tableview.row_height=-1
set ObjCInstance(tv).estimatedHeight to something nonzeroimport ui, faker, random from objc_util import * f=faker.Faker() items=[f.text(random.randint(10,200)) for i in range(20)] class MyTableViewDataSource (object): def tableview_number_of_rows(self, tableview, section): # Return the number of rows in the section return 20 def tableview_cell_for_row(self, tableview, section, row): # Create and return a cell for the given section/row cell = ui.TableViewCell() cell.text_label.text = items[row] cell.text_label.number_of_lines=0 return cell v=ui.TableView() v.frame=(0,0,320,576) v.row_height=-1 v.data_source=MyTableViewDataSource() ObjCInstance(v).estimatedRowHeight=44 v.present('sheet')
Basically we get auto resizing text cells with basically three added lines of code!
@omz -- providing estimatedRowHeight access in ui.TableView would make this more accessible. -
@jonb incredible. Will give it a shot.
Thanks for helping (...doing all the work) figure this out. I think it's really useful and also a very easy approach!
-
@jonb now... Do you think this is possible to do for a view that is added to the
content_view
of a cell?
Will that require flipping bits?