Lazy Loading in UITableview Sections IPhone - iphone

I have "n" Arrays with Images and I want to display images correspondingly in "n" sections of tableview using lazy loading concept.I know how to display one array images in table containing one section.Can anyone Help me???
Thanks in Advance

You pretty much do the same thing; but rather than return the number if images as rows in tableView:numberOfRowsInSection and return numberOfSectionsInTableView: as 1 - you turn things around. Have tableView:numberOfRowsInSection return 1 (so one section per image) and numberOfSectionsInTableView: return the number of images.
Your tableView:cellForRowAtIndexPath: code sees the same change; rather than take the index from indexPath.row you take it from indexPath.section.
And that is pretty much it.
Dw.

Just:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [yourImagesArray count];
}

Related

How to make dynamically adding of rows when user reached to the last row of the UITableView?

I have a UITableview which shows 10 rows currently which is fixed static. Now I want to add a feature into it. I want to add a more 10 rows to the table when user reach to the last row of the UITableView. I mean currently I am showing fixed 10 rows in the application.
But now I want to add 10 more rows whenever user reaches to the last row of previous UITableview.
Please give me any suggestions or any sample code to achieve my motive. Thanks in advance.
It is actually quite simple. What you need to do is implement the tableView:willDisplayCell:forRowAtIndexPath: method, which belongs to the UITableViewDelegate protocol. This method hits every time a cell is about to be displayed. So, it will let you know when the last cell is about to be displayed. Then you could do something like-
– (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *) cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == [self.array count] - 1) //self.array is the array of items you are displaying
{
//If it is the last cell, Add items to your array here & update the table view
}
}
Another (a bit mathematical) option is to implement UIScrollView delegate methods (UITableView is a subclass of UIScrollView), namely scrollViewDidEndScrollingAnimation: or scrollViewDidScroll:. These will let you know the y-position of the content the user is viewing. If it is found that the bottom most content is visible, you can add more items.
HTH,
Akshay
uitableview is derived from uiscrollview. To achieve your objective, you need to implement scrollViewDidEndDecelerating:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height)
{
// your code goes here
}
}
This will detect a "bouncing effect" like shifting up the visible rows to indicate that one would like to see more.
How would you exactly want to invoke the loading of the additional 10 rows? When a user just scrolls down to see the first 10 that are loaded by default he might not want to load 10 more already.
You may add a "add more" line as the last row of your table. When the user clicks on this one you add 10 more.
(I don't know how one would detect a "bouncing effect" like shifting up the visible rows to indicate that one would like to see more.)
The basic logic would look like this:
in cellForRowAtIndexPath you check if the user clicked on the last line and then invoke your code to add the 10
to actually add 10 more lines you have to call [myTable reloadData]
but before you call you need to increase the returned value of numberOfRowsInSection by 10 and make sure that cellForRowAtIndexPath will correctly return your new lines 11-20
ps if you REALLY want 10 additional rows to be loaded when the user reaches the end of the table you need to invoke the loading of 10 more in cellForRowAtIndexPath or willDisplayCell:forRowAtIndexPath: when it is called for your last line.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [categoriesList count];
}
Here categoriesList is an array. We can add objects to this array and call reloadData in the tableview.

how to implement cyclic scrolling on tableview

Could you please help me with circular scrolling in tableview please.
I want that if I scroll down tableview, the rows should go in the reverse way --
it should appear that move back around (bottom rows go around and now come back down from the top) i.e, cyclic scrolling basically.
How can I do so. Any suggestions please.
Thanx in advance.
You could "fake" the cyclic scrolling repeating the same cells all over again. In the numberOfRowsInSection method, return n times the actual number of rows. Make sure n is big enough.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numberOfActualRows*100;
}
Then in the cellForRowAtIndexPath method (and elsewhere) use the mod operator (%) to return the proper cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger actualRow = indexPath.row % numberOfActualRows;
...
}
You may want to hide the sroll indicator.
self.tableView.showsVerticalScrollIndicator = NO;
You may also want to scoll the table view to the middle before you display the table so scrolling backwards works fine.
[self.tableView scrollToRowAtIndexPath: [NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]/2 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
Of course, the user would eventually hit the bottom or the top if he/she kept scrolling over and over.
This question has already been asked: implementing a cyclic UITableView
I'm copying that answer here to make it easier because the asker hasn't ticked my answer.
UITableView is same as UIScrollView in scrollViewDidScroll method.
So, its easy to emulate infinite scrolling.
double the array so that head and tail are joined together to emulate circular table
use my following code to make user switch between 1st part of doubled table and 2nd part of doubled table when they tend to reach the start or the end of the table.
:
/* To emulate infinite scrolling...
The table data was doubled to join the head and tail: (suppose table had 1,2,3,4)
1 2 3 4|1 2 3 4 (actual data doubled)
---------------
1 2 3 4 5 6 7 8 (visualising joined table in eight parts)
When the user scrolls backwards to 1/8th of the joined table, user is actually at the 1/4th of actual data, so we scroll instantly (we take user) to the 5/8th of the joined table where the cells are exactly the same.
Similarly, when user scrolls to 6/8th of the table, we will scroll back to 2/8th where the cells are same. (I'm using 6/8th when 7/8th sound more logical because 6/8th is good for small tables.)
In simple words, when user reaches 1/4th of the first half of table, we scroll to 1/4th of the second half, when he reaches 2/4th of the second half of table, we scroll to the 2/4 of first half. This is done simply by subtracting OR adding half the length of the new/joined table.
Written and posted by Anup Kattel. Feel free to use this code. Please keep these comments if you don't mind.
*/
-(void)scrollViewDidScroll:(UIScrollView *)scrollView_
{
CGFloat currentOffsetX = scrollView_.contentOffset.x;
CGFloat currentOffSetY = scrollView_.contentOffset.y;
CGFloat contentHeight = scrollView_.contentSize.height;
if (currentOffSetY < (contentHeight / 8.0)) {
scrollView_.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY + (contentHeight/2)));
}
if (currentOffSetY > ((contentHeight * 6)/ 8.0)) {
scrollView_.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY - (contentHeight/2)));
}
}
P.S. - I've used this code on one of my apps called NT Time Table (Lite). If you want the preview, you can check out the app: https://itunes.apple.com/au/app/nt-time-table-lite/id528213278?mt=8
If your table can sometimes be too short, at the beginning of the above method you can add a if logic to exit when data count is say for example less than 9.
I haven't done this myself, but you could try the approach you'd use with a UIScrollView to implement cycling scrolling of views (after all UITableView is a subclass of UIScrollView).
I would do as follows:
Create a UITableView with an arbitrary number of cells (at least 7 but will need more to prevent fast scrolling bumping at the end)
Position your UITableView so the centre cell is visible
Maintain a pointer to the index of the cell you are looking to display
In your cellForRowAtIndexPath: use your pointer to as an offset and add the row to it to get the cell that you want
When the UITableView has stopped moving (your UITableViewDelegate can serve as UIScrollViewDelegate so you can use scrollViewDidEndDecelerating). Set your offset index to the current cell, move the table view back to the centre cell without animation and reload the data.
The issue you will have is if the user keeps scrolling without stopping they will eventually hit the bumpers as the number of cells in the table is reached.
Hope this helps, and please post back if you get this working and it looks at all reasonable.
Regards
Dave
This is very much difficult to implement. However, take a look at the ScorllingMadness, which shows the demo of nested (cyclic) pages in a scroll-view.
You need to use the similar kind of trick here as UITableView is a subclass of UIScrollView.

Add blank cell at end of UITable

I'm trying to add an additional cell for custom content as the last cell in a tableView, without altering the dictionary that creates the other content of the table. I think the place to add it is in cellForRowAtIndexPath rather than adding one to the numberOfRowsInSection, which just crashes if I do.
I get a cellCount from the dictionary that creates the data for the table, then in cellForRowAtIndexPath, I have:
if (indexPath.row == cellCount) {
... stuff goes here
return cell;
}
of course, this never gets called. If I do if (indexPath.row == cellCount -1) it overwrites the last cell with content.
I can get this to work if I add a blank entry into the xml from which I am populating the dictionary, but that's ugly.
Example code would be neat!
The problem here is that tableviews are designed to easily and accurately display the contents of you data-model and you've decided you don't want to do that. You're fighting the API.
The straight forward way to do this would be to put a check in numberOfRowsInSection such that it adds one to the row count when you want to display the input row. Then in cellForRowAtIndexPath: you will need to check if the table view is asking for the input row and return the appropriate type of cell.
From a UI design point, you might want to consider whether this setup is the best. This isn't a standard setup. Is the user going to understand that they can only edit the last row of the table? Will they understand they can't edit the other rows? Does anything in the UI tell them how all this works? Does the user have to scroll to the end of the table every time they want to add data? How long can this table grow? How will displaying a keyboard for the last row of the table affect how table scrolls?
I think it would be a better design to use a footer view to display the text field such that is is visually distinct from the rest of the table. It would be programmatically simpler as well. You wouldn't have to check if the table was asking for the last row every single time it ask for a cell.
Edit:
In thinking about it, perhaps a sectioned table would be simpler. Just put the special row in its own section (with or without a header.) That would simplify you handling of the rows that source from the dictionary because the row count in that section would always be the count of the dictionary. Likewise, you could just check the section attribute of the indexpath to know what cell to return for what row.
First you need to modify the numberOfRowsInSection to return +1. Then in cellForRowAtIndexPath you need to add that extra blank cell.
You need to provide for the extra cell in both cellForRowAtIndexPath and numberOfRowsInSection.
Assuming that cellCount is the actual number of cells in your array then: (a) in cellForRowAtIndexPath return the extra custom cell when indexPath.row == cellCount, and (b) in numberOfRowsInSection you need to return cellCount+1.
Assuming a single section, an example would go something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [journalArray count] + 1; // add 1 for summary
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row < [journalArray count]) {
return [journalArray objectAtIndex:indexPath.row];
} else {
return summaryCell;
}
}

How do I get a Row count from a UITableView

I have a tableview I'd like to customize based on how many rows it has.
If it has no rows, I'd like the background image to prompt the user to add content.
If it has 1 or more rows, I'd like it to have a different background image, in order to display the content.
I'm using a fetched results controller to populate my tableview, by the way.
Any ideas?
Well this is generally very easy to accomplish as you need only to have UITableView properly delegated to your ViewController with appropriate delegate methods included in your .m file.
Then you can anywhere get row count like this:
[tablePropertyName numberOfRowsInSection:SECTION_NUMBER];
where section number is 0 for first section, 1 for second, etc.
In Swift, you can get the UITableView rows count by
yourTableViewName.numberOfRows(inSection: Int)
example:
yourTableViewName.numberOfRows(inSection: 0) // returns rows count in section 0
I agree with Sixten Otto's answer.
[myFetchedResultsController.fetchedObjects count];
However there's more. Above line would return the number of objects regardless the sections. However if you would want to perform this on a table with multiple sections, you would have to call it the following way.
[[myFetchedResultsController.sections objectAtIndex:<section>] numberOfObjects];
You can get the objects for the section like this.
[[myFetchedResultsController.sections objectAtIndex:<section>] objects];
** You have to replace with the number representing the section.
Hope this helps.
I'd recommend taking a look at the documentation for NSFetchedResultsController. It has example code for implementing the methods of UITableViewDataSource (including the ones that say how many sections the table has, and how many rows in each section), as well as documenting the property fetchedObjects, which you could use to see how many raw results you fetched.
[myFetchedResultsController.fetchedObjects count];
tableView.numberOfRows(inSection:) returns numbers of row in section, this method may not trigger fetched results controller's core data query.
let numberOfItems = (0..<tableView.numberOfSections).reduce(into: 0) { partialResult, sectionIndex in
partialResult += tableView.numberOfRows(inSection: sectionIndex)
}

Is there a better way to determine the right size for a UITableViewCell?

I have a UITableView cell that is going to have a variable size depending on it's content (potentially several lines of text).
SInce it appears that heightForRowAtIndexPath is called before I layout the cell, I just guess the correct height by calling [NSString sizeWithFont] on my text string. Is there a better way to set the height after I've laid out the text in the cell and have an idea of exactly what size it should be?
It's going to sound dumb, but ...uh... "layout your cell before you exit heightForRowAtIndexPath" ;)
Seriously, though -- the OS only ever calls this if it's going to be needed (as in: it's about to create the cell & display it on screen), so laying it out & getting ready to display is not wasted effort.
Note, you do not have to do your layout separately, logic-wise. Just make a call to your [self prepLayoutForCellAtIndex:index] within your heightForRowAtIndexPath routine.
If the data is static, you can create a height table and cache the info.
if (0 == heightTable[index]) {
heightTable[index] = [self prepLayoutForCellAtIndex:index];
}
return (heightTable[index]);
Heck, even if the data changes, you can either recalculate the table value in the method that changes the data, or clear to 0 so it gets recalculated the next time it's needed.
I use the following, usually:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath {
UITableViewCell *cell = [self tableView: tableView cellForRowAtIndexPath: indexPath];
return cell.bounds.size.height;
}
Note that I use this for tables where I pre-cache a bunch of rows ahead of time, not for those with a LOT of cells. However, for things like Settings tables, where there are just a few rows, but most likely very differently sized, it works well. For larger tables, I do something along the lines of what Olie suggested.
If you look at SMS.app as example, Apple saves the row height of the cell in the SMS.app sqlite database.