Vaadin Grid recalculateColumnWidths problems - how to make it more consistant - vaadin

In my Vaadin 7 app, I call grid.recalculateColumnWidths(); after loading most grids. I do this because when I was refreshing one particular Grid, I noticed the column width was not changing. This fixed it with this one particular Grid, and probably a few others, but not with all grids. The documentation does not really explain a few things, and I was hoping someone could clarify some things so I can fix the problem:
When is it triggered? In other words, in the cases where it does not work, could it be a timing issue? For Vaadin Flow, I see some people advising doing something like grid.getElement().executeJs("setTimeout(() => { this.recalculateColumnWidths() }, 0)");, so I guess this is a long-standing issue. Also, if you look at the low-level API, you will see that it clearly says that you cannot rely on proper columns widths after calling this function, as it is not done immediately. When I step into it in the debugger, it looks like it adds it to a queue of actions to complete later, so that seems to confirm things. How can I improve my chances of the resize being triggered?
How does it handle columns where I explicitly set the width? If this is documented someplace (in API docs or in some posting someplace), I could not find it. When I stepped into the debugger, it was kind of hard to determine for sure.
If I added a button to force a resizing, calling this recalculateColumnWidths() method, similar to what some users did in Vaadin 14 here, would it work? So let's say we initialize the width to one value (so we purposely truncate some columns, forcing them to make the column bigger), and we want to fully show all content in all columns when they click this button, is there a way to do that? Maybe clear all explicit column sizes and let normal resize logic work?

Let me preface this answer by saying that column width (re)calculation is a complex and relatively expensive task. It needs to be done at the right time - not too early and not too late. If it's done too early, subsequent changes to layouting will mean that size calculation will need to be done again. If it's done too late, it means that the UI will take longer to become responsive again. Trying to "play it safe" by doing column width recalculation more often than needed is an easy source of performance degradation - a Grid can have a LOT of columns, so the cost of recalculation compounds easily.
There are many cases when column width recalculation is triggered. A couple of basic cases are during the layouting phase of the UI, or when a Grid is reattached, or when the inner width of the Grid changes (e.g. due to browser window resize), or when something is done to column sizes (e.g. min or max-width or expand ratio are set). Resizing is indeed queued as you can see here: https://github.com/vaadin/framework/blob/7.7/client/src/main/java/com/vaadin/client/widgets/Grid.java#L3280. It's definitely possible that there's a timing issue. Without the exact conditions of how a calculation goes wrong, it's hard to say when would be a good place to retry - there's no place where "everything is truly finally rendered so that you can schedule a little bit more rendering".
The size of fixed-width columns will not need to be calculated, so these columns should be ignorable from this point of view. In fact, if you can set a fixed width to all or most columns, it will most likely mean a significant performance improvement.
Yes, it could work.

Related

Lazy loading old messages with NSFetchedResultsController while doing realtime communication

Consider a chat application scenario, where you have a very large group with 100,000+ messages and realtime communication.
Just like most chat applications, we want the latest messages to appear at the bottom i.e. new items are added at the bottom.
What's the best practice for using lazy loading with NSFetchedResultsController? Changing the fetch-request by increasing the fetchLimit doesn't seem like a good idea. Also, using an extra array instead of fetchedObject also doesn't seem like a very elegant or convenient solution either.
What's the best practice for showing latest messages at the bottom i.e. reversing the UITableView direction? Transform doesn't seem to be an elegant solution, or is it?
Looking for an elegant solution, that's working for people. Please advise.
fetchLimit doesn't work with NSFetchedResultsController. To limit the controller you can do the following:
Do a single fetch with a fetchLimit=1 and a fetchOffset=BATCH_SIZE (where the batch size is something large, but not huge = ~200)
get the date of that message that you fetched
limit the fetchedResultsController to the date of that message.
Now you have a fetchedResultsController that is 200 messages. Note that it may increase in size as long as it is open.
When a user scroll back you can do some similar adjusting of the fetchedResultsController by doing a fetch to figure out a correct date range.
For display the cells I have used the double-inverse method (apply a 180 rotation to the collectionView and a 180 rotation to every cell). It is not that elegant but it works and it is not as expensive as it first seems - the whole screen is already in an openGL layer behinds the scenes anyways. There are a lot of little things that it caused (like the scrollIndicator being on the wrong side), but also a lot of little things that it fixed (like dealing with a chat with very few messages). If I had to do it again I would make a custom layout, but I wouldn't be so quick to dismiss the double-inverse method.

Is it possible to change the sensitivity/pull distance of a UIRefreshControl?

I have a UITableView displaying a table of data with a somewhat large contentInset value. As a result, the user cannot trigger the UIRefreshControl because it expects them to scroll too far.
Basically, I'm wondering if it's possible to make UIRefreshControl adjust for contentInset values.
Edit: This question is mostly about curiosity, so I removed the extra details and rephrased the question to be more direct.
I think you're going about this a bit wrong. If you've encountered this issue because of the mechanism you've created to preload cells, you should think of a different approach for preloading them. If there's any content to be rendered / loaded / downloaded, you could be doing this in a background thread and leave a minimal amount of work for cellForRowAtIndexPath. If you insist on keeping this implementation, I'd suggest looking up a custom refresh control as there is no way to customize the build in UIRefreshControl in terms of content offset for refresh (AKA sensitivity). I believe this is ultimately a good thing - there should be consistent user experience across apps running on iOS which use a refresh control.

iOS, fast way to generate clickable, multicoloured text

I need to generate a text container that contains something like this:
This is some random text
where a few of the words are
coloured and clickable
The clickable words should have different actions bound to them and should be in a certain colour. The container will have a fixed width and I need to know the resulting height of the container given a certain text.
What I've tried: Tried making each word a separate UILabel, added actions where actions were needed, calculated line breaks myself. The problem with this approach was that it was too slow, especially UILabel sizeThatFits. I need to generate a lot of text for a scrolling UITableView and this approach killed the scrolling performance.
What I also tried: UIWebView. For a few different reasons, it's just not an option.
What I would prefer: A solution that does not require third party code. This is optional, though if they are open source. iOS 7-only solutions are acceptable.
Lastly, what needs to be fast is the generation of the text and the measuring of its height. Determining where to click is allowed to take some time.
See that https://github.com/mattt/TTTAttributedLabel
..but i not understood about height
If iOS only is an option, watch the WWDC 2013 session 210 "Introducing Text Kit". They show things that are at least very similar to what you are asking for.

iOS7 UIPickerView / UIScrollView

I'm using a UIPickerView in a somewhat unorthodox way to allow users to select a series of images (in this case, they're words on a background, but they can just easily be pictures):
Under iOS6 this worked great, but with iOS7 as you can see, the edges of the images fade to white, which makes the control unusuable for this purpose.
My question are --
a) Would there be a way of "fixing" this and still using the UIPickerView control? If so, what kind of approach might one take?
b) If I can't modify the views to eliminate the problem, would a practical alternative to be to use three UIScrollViews to replicate this functionality?
c) I have at times modified the views presented in a UIPickerView, and I'm considering trying to do that here, i.e., to just plug in my own replacement views. But I'm unclear on whether that is practical... I'm questioning how the blur effect is added to these views at the top and bottom and how I might go about eliminating them.
That's a lot for one post; I'm just trying to decide what the best approach might be to deal with this issue.
TIA for any suggestions or guidance...
I ended up making some adjustments to the implementation that improved the appearance somewhat. We slightly increased the overall size of the picker by scaling it 1.25 (when in portrait view) or 1.40 (when in landscape view). At the same time, I slightly reduced the size of the images in the picker. The end result was that overall the frame was bigger, but the images were about the same size as before. But the regions where the appearance is blurred are safely out of view unless one really looks hard for them. We have judged this will work for now.
Ultimately, the UIPickerView has, in our opinion, taken a huge step backward with ios7. We are anticipating the need to write something of our own to accommodate our needs in the long run but these changes have allowed us to get by for now.

Best approach for UITableViewCell with complex format

I'm new to iOS development pondering how best to approach a fairly simple design problem. I want to display a set of items, each one of which has the structure as sketched. In a given set, not more than 10's of items.
Each item includes a thumbnail image, a heading, a blurb, and a set of buttons. There are two complications:
The amount of text and number of buttons is variable.
The text requires some internal formatting (italics and bold).
I've considered these approaches:
Use a table view, with custom, resizable UITableViewCell, probably using something like OHAttributedLabel for the text. For the variable number of buttons, either lay these out programmatically or possibly use the new collection view (for older iOS, have to use 3rd party grid view).
Use a table view with custom cell based on UIWebView.
Do the whole set as one UIWebView.
Use a table view with sections; each item having its own section and parsing out the buttons and text to rows.
Would love to get suggestions about how a more experienced iOS dev would approach this.
EDIT: I am now considering that the best way may be:
5) Use UICollectionView for the whole thing.
UPDATE: In the end, I laid the whole thing out in code as a custom table cell (ie., #1). This was a good choice, not only for the reasons given in the answer, but because as someone new to iOS development, it's something I needed to get under my belt. Didn't even use collection view for the buttons, because I was worried about performance and also the hassle of supporting iOS5.
I do think that using collection view for the whole design (#5) would have been an elegant solution, and I actually started down that path. However, some complications not shown in the simplified pic above made that unwieldy.
2nd UPDATE: #1 turned out to be a dead end. My final solution used a UIWebView (#3) - see answer.
I have found some resources that might be useful to some people who is doing complex tableviewcell and want fast scrolling. I am still developing it, but I want to share this first to you guys.
Facebook iOS release note: they mentioned techniques: core text, pre/asynchronous calculation of table height, do a lot of things on background thread, save layout attribute in core data. http://www.facebook.com/notes/facebook-engineering/under-the-hood-rebuilding-facebook-for-ios/10151036091753920
Fast scrolling sample: https://github.com/adamalex/fast-scrolling
Apple's sample project TableViewSuite. The 4th example.
https://developer.apple.com/library/ios/#samplecode/TableViewSuite/Introduction/Intro.html
Very close to solution..YES
I know this is an old thread, but I found it very interesting, as I am just now getting around enough as an iPhone developer to reach these types of performance concerns. I found a very interesting article on Facebook's site by Facebook Engineering describing how they implemented UITableView and overcame the dynamic sizing issues, also with rapid content management. It seems they precalculated using deeper objects and kept everything asynchronous and pre-cached where possible. I'm going to provide a link to the article, but I'm going to copy the section that tackles exactly this problem. I hope you find it useful. Here's the link, https://www.facebook.com/notes/facebook-engineering/under-the-hood-rebuilding-facebook-for-ios/10151036091753920, and the most relevant excerpt:
(Re-)Building for Speed
One of the biggest advantages we've gained from building on native iOS has been the ability to make the app fast. Now, when you scroll through your news feed on the new Facebook for iOS, you'll notice that it feels much faster than before. One way we have achieved this is by re-balancing where we perform certain tasks. For example, in iOS, the main thread drives the UI and handles touch events, so the more work we do on the main thread, the slower the app feels. Instead, we take care to perform computationally expensive tasks in the background. This means all our networking activity, JSON parsing, NSManagedObject creation, and saving to disk never touches the main thread.
To give another example, we use Core Text to lay out many of our strings, but layout calculations can quickly become a bottleneck. With our new iOS app, when we download new content, we asynchronously calculate the sizes for all these strings, cache our CTFramesetters (which can be expensive to create), and then use all these calculations later when we present the story into our UITableView.
Finally, when you start Facebook for iOS, you want to see your news feed, not a loading spinner. To provide the best experience possible, we now show previously-cached content immediately. But this introduces a new problem: If you have a lot of stories in your news feed, UITableView throws a small spanner in the works by calling the delegate method -tableView:heightForRowAtIndexPath: for each story in your news feed in order to work out how tall to make its scrollbar. This would result in the app loading all the story data from disk and calculating the entire story layout solely to return the height of the story, meaning startup would get progressively slower as you accumulate more stories.
The solution to this particular problem has two main parts. Firstly, when we do our initial asynchronous layout calculations, we also store the height of the story in Core Data. In doing so, we completely avoid layout calculation in -tableView:heightForRowAtIndexPath:. Secondly, we've split up our "story" model object. We only fetch the story heights (and a few other things) from disk on startup. Later, we fetch the rest of the story data, and any more layout calculations we have to do are all performed asynchronously.
All this and more leads to high frame rates while scrolling and an app that remains responsive.
I originally accepted (and implemented) #Daij-Djan's answer, but now I believe the best approach is #3 (UIWebView). It comes down to performance.
UITableView strains to perform well with custom cells with subviews, especially in the context of cells with varying heights. The rows of buttons make the scrolling choppy. As suggested by Apple in Cells and Table View Performance , I made sure that subviews were all opaque, however there is no way to follow the suggestion of "Avoid relayout of content."
Add onto that dynamic cell heights and attributed strings and these tables scroll pretty poorly. I suppose the next optimization would be to override drawRect, but at that point I decided to try UIWebView.
UIWebView is not without its performance issues either! Its scrolling performance degrades pretty fast as the content grows, however, I can manage that by hiding content and letting user "open" it as desired.
no 1 is maybe the most work directly followed by #2 BUT
as ACB said, it's also the most flexible and IMO will surely provide the best look'n'feel
no 3 works but will not feel as smooth / alway be tad 'html-ish'
no 4 sounds like highway to hell (later on. it will be a PITA to modify/maintain)

Resources