Loading more rows in the tableview - iphone

I need to load 15 records initially and then when the user clicks on the show more row of the cell, i need to load the next 20 or available records in my tableview. I am looking at this question posted in SO.
This functionality can be seen in appStore too. Where you load the next number of records.
Here the solution is;
`- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.numberOfRowsVisible;
}
-(void)moreButtonClickAction {
if (self.numberOfRowsVisible < self.maxNumberOfRows)
self.numberOfRowsVisible = MIN(self.numberOfRowsVisible + 10, self.maxRows);
[self.tableView reloadData];
}
I initialized and hard coded the value in the viewDidLoad for numberOfRowsVisible as 15.
self.numberOfRowsVisible=[NSNumber numberWithInt:15];
in numberOfRowsInSection - i am not sure if this is correct.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return MIN([self.arrayRecords count], 15);
}
in the moreButtonClickAction
-(void)moreButtonClickAction {
if (self.numberOfRowsVisible < [self.arrayRecords count])
self.numberOfRowsVisible = MIN(self.numberOfRowsVisible + 15, [self.arrayRecords count]);
[self.tableView reloadData];
}
This is how i edited my code to suit the above suggestion left in SO. but this is not working. There seems to be some issue with MIN. I am not in MAC at the moment, so i can't remember the exact warning/error i got. So could someone kindly help me out.

1) Don't use an NSNumber object, a plain integer will do.
2) Why not just have an integer variable that shows the current number of rows that you want to display, and initialize with 15, and keep it in your class instance.
3) You don't even have to use MIN:
return [self.arrayRecords count] < self.numberOfRowsVisible ? [self.arrayRecords count] : self.numberOfRowsVisible;

You have to use MAX instead of MIN if you want to show all possible entries.

numberOfRowsInSection should return an integer.
self.numberOfRowsVisible is not an integer.
viewDidLoad:
self.numberOfRowsVisible=15;
main implementation:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.numberOfRowsVisible;
}
-(void)moreButtonClickAction {
if (self.numberOfRowsVisible < [self.arrayRecords count]) {
self.numberOfRowsVisible += 15;
if (self.numberOfRowsVisible > [self.arrayRecords count]) {
self.numberOfRowsVisible = [self.arrayRecords count];
}
}
[self.tableView reloadData];
}
off the top of my head, code could do with re-factoring.

Related

Resizing tableview's first visible section header height

I created a UITableView that contains custom section header views. Now, I want it to display a bit more data on the uppermost current visible section. I plan to use the event scrollViewDidEndDecelerating to update the section headers. Currently, the problem is that I cannot set the section header height for a specific section number.
I did try using heightForHeaderInSection beforehand, but the app just crashes with the following output:
'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
I was using the code:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (tableView == self.tableView)
{
NSArray *visibleCells = [self.tableView visibleCells];
NSMutableArray *visibleSections = [[NSMutableArray alloc] init];
for (NSInteger index = 0; index < [visibleCells count]; index++)
{
UITableViewCell *currentCell = [visibleCells objectAtIndex:index];
NSIndexPath *currentPath = (NSIndexPath *)[self.tableView indexPathForCell:currentCell];
if (![visibleSections containsObject:[NSNumber numberWithInt:currentPath.section]])
{
[visibleSections addObject:[NSNumber numberWithInt:currentPath.section]];
NSLog([NSString stringWithFormat:#"%ld", (long)[visibleSections count]]);
[visibleSections sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:nil ascending:YES]]];
}
}
if (visibleSections == nil)
{
return 42.0;
}
else if ([[visibleSections objectAtIndex:0] integerValue] == section)
{
return 58.0;
}
else
{
return 42.0;
}
}
}
I couldn't quite work out what went wrong in my heightForHeaderInSection method, but I knew it had something to do with the NSMutableArray, visibleSections.
Any hints or answers as to how I can go about changing the height for a specific section header view outside of heightForHeaderInSection and/or how I can fix my code above would be really helpful.
Edit:
Just to make the solution to my crashing problem a bit clearer, if (visibleSections == nil) should not be used in place of if ([visibleSections count] < 1) or if ([visibleSections count] == 0).
I think you could also do it like this, if you want the first section header to be taller when the table first appears (topSection is an NSInteger property):
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.topSection = ((NSIndexPath *)[self.tableView indexPathsForVisibleRows][0]).section;
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:self.topSection] withRowAnimation:NO];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (self.topSection == section)
{
return 58.0;
}
else
{
return 42.0;
}
}
OK so it turns out this is a harder problem than it first seems. The best I have come up with so far is
Don't treat the header that is for the top section any different and populate them all with the extra data.
You can show and hide different parts by being clever with positioning the "additional" items so that they will be outside of the parent view's bounds when it is smaller and making the parent view clipToBounds.
Failing that you can make a custom UIView subclass and do some manipulation in layoutSubviews
The end implementation I was settling on was this
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
self.topSection = [indexPaths count] ? [indexPaths[0] section] : -1;
if (indexPaths.count > 1) {
self.topSection = [indexPaths[1] section];
}
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
{
if (section <= self.topSection) {
return 60;
} else {
return 20;
}
}
It's by no means perfect but it looked semi reasonable and could be tweaked.
Things to note:
You may need to assess if there is too much work going on in scrollViewDidScroll: but it didn't appear to cause any lag for me (I've not really tested properly)
I set the top section using the second indexPath if available as it looked slightly more pleasing/less clunky
I use section <= self.topSection because the header's before are all of screen so there is no point in reducing the size of them which causes really clunky animation.
So after trying this you may need to dig deeper or want to rethink your design a little
You cannot directly refer to the arrays first object by calling objectAtIndex:0, you gotta stay defensive so change this:
else if ([[visibleSections objectAtIndex:0] integerValue] == section)
{
return 58.0;
}
To
else if([visibleSections count]>0)
{
if ([[visibleSections objectAtIndex:0] integerValue] == section)
{
return 58.0;
}
}
Try changing this line:
NSMutableArray *visibleSections = [[NSMutableArray alloc] init]
to:
NSMutableArray *visibleSections = [NSMutableArray array];
Which initializes the array.

Odd numberOfItems in UICollectionVIew

I am using UICollectionView and my app crashes because I have odd number of items in my list but while I need to tow the items in section.
This is my the numbet of items in every section:
(NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
return 2;
}
Here is the problem:
In my list i have 3 items and when the objectAtIndex is 3 the app crashes
MSCoupon *coupon = [list objectAtIndex:indexPath.section * 2 + indexPath.row];
Do you have any solution for me?
This is happening because collection view is trying to access the 2nd element of 2nd section. which resulting in crash because your formula creating index 3.
For second element of section section Your formula
indexPath.section * 2 + indexPath.row
gives
1*2 + 1 = 3
Since your array have 3 element only it will through exception when you try to access fourth element.(array index start with 0).
In Collection view delegate you write this formula. leave rest of your code un-touch it should work
(NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
return (list.count/(section + 1)) >= 2? 2: 1;
}
My solution is as follows:
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
//return 2;
return [list count];
}
and:
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
//return [list count]/2;
return 1;
}
Do you have a better advice for me?

custom amount of cells in each tableview group

How would I be able to customize the amount of cells in each tableview group? Basically, I need 2 cells in the first group, 4 cells in the second group, and one cell in the third. I can't seem to find anything, which is odd, unless I'm calling it the wrong thing. Thanks in advance. :)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0)
return 2;
else if (section == 1)
return 4;
else if (section == 2)
return 1;
}
Number of cells in each table section is specified in table's data source tableView:numberOfRowsInSection: method. Somewhat dummy example for your case:
- (int) numberOfSectionsInTableView:(UITableView*)tableView{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
int numbers[] = {2,4,1};
return numbers[section];
}

UITableView Section Header issue

All,
I have a grouped UITableView with a possible total of 3 sections. There could be 1, 2 or 3.
My issue is that for each section I use a different header & footer view. I am choosing which header/footer to show by checking the section #.
This obviously does not work, as section 0 does not always represent what 'header' 0 shows.
Example:
Header #0 = "Game in progress". But no games in progress are returned from the database. Only 'Games Ended" exist. Therefore section 0 would be all 'games ended'. I don't want 'Games Ended' to use the 'Games in Progress' header.
I can't find a way to check the section value, and not the number.
To put it simply, I would like to be able to show section header #3 for section name #3, even if section name #3 is section #0.
I know this seems trivial, and is probably simple... but I am stuck. Any help is appreciated.
Thanks.
----- CODE -----
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[fetchedResultsController_ sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController_ sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if(section == 0)
{
return 50.0f;
}
else if (section == 1)
return 50.0f;
else
return 50.0f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
if(section == 0 )
{
return 50.0f;
}
else if (section == 1)
return 5.0f;
else
return 80.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if(section == 0)
{
return headerView1;
}
else if (section == 1)
return headerView2;
else
return headerView3;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
if(section == 0)
{
return footerView1;
}
else if (section == 1)
return footerView2;
else
return footerView3;
}
Obviously, deciding which header / footer to show by checking the section # is wrong (this is bad MVC). For a solution to your problem, it would be better to see some actual code, although I think I can suggest something in general:
The sections that you show are taken out of some data source - an array, a dictionary or some other collection (this is the same collection you use to determine, for example, the return value for the numberOfSectionsInTableView: delegate method. If you haven't done so already, you should incorporate these data instances into some object that contains the data itself (this is the data that you normally need for displaying the cell/header/footer elements along with the actual data values) - In this object, add an additional "HeaderType" enumerated value, so that each object "knows" how it is supposed to be displayed. This way your MVC is perfect: You have your data stored in a collection of custom objects, your controller knows how to display the data by it's type and of course your view shows the data properly based on the controller's instructions.
Here is an example of an enumeration that could help:
typedef enum {
kHeaderTypeGameProgress,
kHeaderTypeGameStats,
kHeaderTypeGameDate
} HeaderType;
In your "viewForHeader" or "viewForFooter" methods, just add a switch type to check the data's HeaderType and create a view accordingly. Hope I helped, good luck!
It seems that in your cellForRowAtIndexPath, you must already have some logic that decides what group to show data from, maybe something like:
NSArray *group;
int section = indexPath.section;
if (![gamesInProgress count]) section++;
switch (section) {
case 0:
group = gamesInProgress;
break;
case 1:
group = finishedGames;
break;
// etc.
}
In your viewForHeaderInSection, write similar code that sets a NSString instead of NSArray.

Section index in table view

I am implementing a table index view and amazed to see how my table indexes are working even without implementing:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index method.
I have only implemented:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
Strangely, when I am running in breakpoints, Once i click on any of the index values my
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method is getting called.
Any clue why this is so happening and what is the significance of sectionForSectionIndexTitle method then.
if you have a list of all letters in alphabet and your list only contains some entries, you could use the following code:
//Asks the data source to return the index of the section having the given title and section title index.
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
if (tableView == self.searchDisplayController.searchResultsTableView || self.searchBar.text.length > 0)
{
return 0;
}
else
{
//direct - firsttime match
if([self.realMIndexArray containsObject:title]) {
NSInteger count = 0;
for(NSString *character in self.realMIndexArray)
{
if([character isEqualToString:title]){
return count;
}
count ++;
}
}
else {
//take next higher letter from alphabet and check if its contained in the "available letters list"
//if not, select last entry of list
for(int i = [self.indexArray indexOfObject:title] + 1; i < [self.indexArray count]; i++) {
NSString* character = [self.indexArray objectAtIndex:i];
if([self.realMIndexArray containsObject:character]) {
return [self.realMIndexArray indexOfObject:character];
}
}
return [self.realMIndexArray count] - 1;
}
return 0;// in case of some eror donot crash d application
}
}
realMIndexArray count == letters really existing in list
indexArray = list of all letters in alphbeth.
hope this helps someone (took me a little bit of time to figure it out)
Any clue why this is so happening
Yes. When you tap (you do not click on an iPhone) on a table's index, the underlying table view will want to jump to that section, and the cells in that section. In order to do that, it has to ask the data source for those cells so it can render them on the screen.
what is the significance of
sectionForSectionIndexTitle method
then.
The documentation for tableView:sectionForSectionIndexTitle:atIndex: (which is an optional method in the UITableViewDataSource protocol) says:
Asks the data source to return the
index of the section having the given
title and section title index.
and
You implement this method only for
table views with a section index
list—which can only be table views
created in the plain style
(UITableViewStylePlain).
Does this apply for your UITableView? In other words, are you using a grouped table view style?