UITableView Scroll when new cells are added - xcode

In my app I have a pull down to refresh feature. Basically what this does is it adds some more cells to the top of my UITableView. However when I do this the screen automatically scrolls down. I want to keep my position on the screen when the new cells are loaded.
[dataPosts insertObject:[[MainButton alloc] initWithFrame:CGRectMake(0, 0, 320, 260) withData:0 hasNick:[self createRandomStringWithLength:140]] atIndex:0];
dataPosts is the data array of my UITableView. MainButton is a UIView with size 320,260 and it is added as a view into a UITableViewCell. So whenever I add a new entry to my data, the table automatically scrolls down 260 units but I want my position to stay the same. Thanks in advance.
-C

When the new rows are to be inserted you are aware how many rows are going to be inserted. So based on that you can call scrollToRowAtIndexPath:atScrollPosition:animated: method of UITableView to be at the same place even when new rows are inserted at the top.
E.g:
Currently 10 rows are displayed and 1st row is at the top.
Now suppose, new more 20 rows are to be inserted. Insert them without animation.
Now, call above mentioned method with indexPath.row of 21 without animation.
Hope that helps. Let me know if you are looking for something else.

Related

Pre-creating UICollectionView cells - layout issue

I have a UITableView with 6 rows. Each row contains a single UICollectionView. Each collection view contains a single section with 10-15 cells. One view controller is the datasource and delegate for both the table view and the collection view.
I would like to address some performance issues when scrolling the tableview. Whenever a new section comes into view, there is a small pause while the collection view is created and filled. Since I have a fixed number of cells (< 100) and they are almost static (they are initially loaded from a web API but the data will change only a couple of times a week), I would like to pre-build each of the collection view cells in advance. I would prefer the user waits an extra half-second on launch than encounters jerky scrolling.
To accomplish this, I have updated my collectionView: cellForItemAtIndexPath: to check a dictionary of cells I am maintaining. It looks for a key composited from the collection view index and the indexPath for the cell. If the key exists, the corresponding object is returned. If none is found, the cell is built and also added to the dictionary. This step effectively prevents cells from being un-loaded and recycled, at the expense of using more memory.
But on launch, I still need to run this once for each cell to pre-populate the dictionary. I iterate over each table view cell, find the collection view, and call
[self collectionView:collectionView cellForItemAtIndexPath:indexPath];
This is almost enough. The cells are being created and stored in the dictionary, and when I scroll to a new collection view, I see that they are being pulled from the dictionary and are displayed. But all of the cells, and all of their contents, are shoved up in the top-left corner at {0,0}.
Some logging tells me that at the time the cells are created, the frame of the collection view is {{0, 0}, {0, 0}}. I assume this is why none of my layout is being applied?
How can I resolve this?
(Would also be interested in any general comments on my pre-loading implementation).
I resolved this by calling [cell layoutIfNeeded] on the UITableViewCell (not the collection view). A more thorough explanation is welcomed.

making insertRowAtIndexes:withAnimation visible when inserting new row at end

I'm using insertRowAtIndexes:withAnimation to add a new row to an NSTableView.
If the rect of the new row is already visible then this works fine but there is a problem when inserting a new row at the end. The row gets inserted as expected but since the scroll position doesn't adjust, the animation happens offscreen!
Any obvious fix I'm missing?
You have to make the new row visible manually. You can't call -rectOfRow: on the row you are inserting, because it's not in the table yet -- instead, look at the rect of the last row in the table, add the expected height of the new row, and then see if the resulting rect will be visible onscreen; if not, you need to scroll.
See NSTableView scrollRowToVisible with animation if you want to animate the scroll. Note that on 10.7+ you probably want to call -flashScrollers on the scrollview as well.

titanium functionality

I'm new to titanium and I,m trying to build some prototypes based on wireframes. Below is the wireframe that I'm trying to build as prototype.
What you see is a list of restaurants fetched from google places api. The main functionality here is the black strip which will be at a fixed position and holds the details of rating and reviews on a particular restaurant which is underneath it.
So if I scroll through the restaurants the black strip should get the rating details of that particular restaurant which is underneath it.
So far I was able to crawl the restaurants data from google places api into row of the table view.
I'm not sure what to call this functionality or how to achieve this.
Can you guys please give me direction to proceed ahead...
#Sarat,
I assume you wanted to develop this Prototype for iOS or Android App, so using Titanium I've below suggestion for design & functionality
To Achieve Design:
For Android - Use Relative Layout with List view which you can load Rating/Review Icons on top with Fixed Position
For iOS/iPhone - Add Parent VIEW and then Add Table VIEW to load Restaurant and Add Rating/Review Icons in Another Table VIEW with Same Top position of Restaurant List
To Achieve Functionality:
You will get First cell index of Table View in which Restaurant List you're loading, so keep check which Cell of Table is on Top of Table view using Cell Identifier.
Wouldn't it be much easier to just include it as a part of the row? Otherwise the user can only see one rows information at a time, which I would consider bad design.
More importantly, this will not work on iOS unless you add a lot of dummy table rows at the end of the TableView, since the user wont be able to scroll the bottom-most row to the top of the screen!
This tutorial shows you how to have custom table rows. Use it as a starting point to add your comment and like button images. I really see no other alternative, since your fixed position method requires hacking the TableView component or using transforms to move the bottom row to the top.
EDIT:
If you must do it this way, the best way forward would be to add a number of blank table rows to past the end of your real table rows so that the user can scroll all the way down to the last row with content (this way the fixed position can detect its over it).
Next create your view holding the three buttons, making sure its absolutely position in the window (so it stays fixed) and has a zIndex greater than the TableView:
var likeAndCommentHolderView = Ti.UI.createView({
top : 45,
left : 0,
//.... etc
zIndex : 101
});
window.add(likeCommentHolderView);
Now you have to figure out which row the user is over. This can be done using the scrollEnd event of a TableView and getting the contentOffset attribute of the event. The 'scrollEnd' event is triggered when the user has finished scrolling the rows in a tableView, it returns an event that has the contentOffset, which is just a measure of how much you have scrolled from the top of the tableView. Using simple math, calculate the offset divided by the rowHeight and that is the row index the user is looking at.
// Assume table view is at coordinates : top=45, left=0 and you have defined rowHeight
tableView.addEventListener('scrollEnd', function(e) {
// Use this to determine which row your over
var contentOffset = e.contentOffset;
// Figure out the index
var rowIndex = contentOffset / rowHeight;
// Get the row, assume first section
var section = tableView.data[0];
var rowObject = section.rows[rowIndex];
// Now update your UI with data from the row
var name = rowObject.restaurantName;
});
Now you have the actual row object in the table, you can extract
This is only a general outline, this does not take into account some of the differences between platforms, I leave that to you to figure out, but this is a good general approach.

View-based NSTableView renders blank rows after inserting new rows with animation

I have a view-based NSTableView that I'm backing with an `NSMutableArray . Periodically I go out grab some data and want to insert new rows into the table at the top.
When I do this without specifying an animation to insertRowsAtIndexes:withAnimation: it seems to work fine for hours on end. However, if I specify an animation, after about 7 or 8 inserts the table view starts to show blank rows where the inserts occurred. Scrolling down and then back up causes the new rows to render properly.
The code that calls insertRowsAtIndexes:withAnimation is in a block, and not running on the main thread, but my inserts happen inside of dispatch_async on the main queue, so I dont' think it related to multithreading.
Here is some code ... self.contents is my NSMutableArray.
dispatch_async(dispatch_get_main_queue(), ^{
[self.contentsTableView beginUpdates];
if(posts.count) {
for(NSDictionary* dictionary in [posts reverseObjectEnumerator]) {
FNPost* post = [[FNPost alloc] initWithDictionary:dictionary width:self.contentsTableView.frame.size.width];
post.delegate = self;
[self.contents insertObject:post atIndex:0];
[self.contentsTableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:0] withAnimation: NSTableViewAnimationSlideLeft];
}
}
[self.contentsTableView endUpdates];
});
One thing I'm confused about is the part of the Apple NSTableView documentation for insertRowsAtIndexes:withAnimation that says:
The numberOfRows in the table view will automatically be decreased by
the count of indexes.
I'm confused by what that statement implies about the relationship between the number of objects in my array (and hence the result of numberOfRowsInTableView:) and the number of rows the table view thinks it has. To my thinking the number of rows in the table view should equal my array count and I want to make sure that my understanding of this is not at the root of the problem but like I said, the table works fine if no animation is specified.
Am I doing something obviously wrong here?
This issue turns out to be caused by having the NSTableView in a layer based view hierarchy. Two superviews up, I had a layer-backed view. After reading some other posts about NSTableView showing other errant behavior when in a layer-backed hierarchy I decided to turn off the layer in IB. Table animations now occur as I would expect at the expense of having to maintain some additional state to control the layer backing state when I want to use CA transitions between my views.

how to keep the visible content after nstableview reloaddata?

I have a subclassed nstableview whose data source array may increase, by calling reloadData: I can refresh to reflect the data updating.
But after reloadData:, the tableview will always scroll to the new cell with the same old row number (for example, if the tableview was showing the 2nd cell, after reloadData:, the tableview will scroll to the new 2nd cell, therefore, the visible content of the tableview will change). How can I disable this automatic behavior and keep the visible content unchanged after the updating?
thanks in advance!
Table views don't re-scroll when their content changes. Since you're changing the table content which underlies the currently displayed rows, you need to move the scroll yourself.
I don't have code for this, but I suggest using rowAtPoint: to find the initial position of the table view, identifying or calculating the new row index for that row's content, and then calling:
[tableView reloadData];
[tableView scrollRowToVisible:newIndex];
I got this problem fixed: first, I got the rect size changed amount; then after the reloadData: , scroll the tableview to the changed point (original point + delta parts) immediately with the clipview's scrollToPoint: method. It does it so fast that you cannot realize the operation there.

Resources