I've seen a lot of examples, but I still havn't managed to get mine working.
I have 1 array I'm populating from NSUserDefaults. Everything works as it should. However I wanted the ability to move a row into the empty top section. Like pinning a note.
I am able to move and save the rows in their current section, but moving will not apply the change.
Relevant code:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
//if (sourceIndexPath.row != destinationIndexPath.row && sourceIndexPath.section != destinationIndexPath.section) {
//return;
if ( sourceIndexPath.row != destinationIndexPath.row )
{
id noteObject = [self.noteArray objectAtIndex:sourceIndexPath.row];
self.noteArray = [noteArray mutableCopy];
[self.noteArray removeObjectAtIndex:sourceIndexPath.row];
[self.noteArray insertObject:noteObject atIndex:destinationIndexPath.row];
id dateObject = [self.dateArray objectAtIndex:sourceIndexPath.row];
self.dateArray = [dateArray mutableCopy];
[self.dateArray removeObjectAtIndex:sourceIndexPath.row];
[self.dateArray insertObject:dateObject atIndex:destinationIndexPath.row];
[self performSelector:#selector(delayedReloadData:) withObject:self.tableView afterDelay:0.02];
return;
}
}
This gets called if I move rows, but not into the section.
- (void)delayedReloadData:(UITableView *)tableView
{
[[NSUserDefaults standardUserDefaults] setObject:self.noteArray forKey:#"note"];
[[NSUserDefaults standardUserDefaults] setObject:self.dateArray forKey:#"date"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.tableView reloadData];
NSLog(#"Move Row Update");
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger numOfSections;
if ([self.noteArray count])
{
tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
numOfSections = 2;
tableView.backgroundView = nil;
}
else
{
UILabel *noDataLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, tableView.bounds.size.height)];
noDataLabel.text = #"No data available";
numOfSections = 1;
noDataLabel.textColor = [UIColor systemGrayColor];
noDataLabel.textAlignment = NSTextAlignmentCenter;
tableView.backgroundView = noDataLabel;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return numOfSections;
}
This may be the issue? Not sure how to account for an empty section
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
return;
}
if (section == 1) {
return [self.noteArray count];
}
return section;
}
Any help would be greatly appreciated. Thank You.
Related
how to reload the data in the table while scrolling?
If i have a url "http:.......&start=0&limit=50".
How to reload the data in table with incrementing the start and limit value with 50.
Can anyone find a solution for this?
You need to implement the load more functionality in the table view for this.In order to do so, you need to track the table view's index while it is scrolling once table reaches the last cell you can call the api with increased page number and add the new records to the array once you get the positive response from the api.
See the below code for more understanding.
Variable initialization
#interface ExampleListVC (){
BOOL hasNextPage,isLoadingNextPage;
int currentPage;
NSMutableArray *arrTableData;
}
#end
In viewDidLoad method
arrTableData = [[NSMutableArray alloc]init];
currentPage=-1;
hasNextPage = YES;
In tableView numberOfRowsInSection method
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = (int)arrTableData.count;
if (hasNextPage)
{
count++;
}
return count;
}
In cellForRowAtIndexPath method
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
if (indexPath.row<arrTableData.count)
{
//Load TableviewCell you intend to show
}
else
{
//Show loading cell
cell = [self loadingCell:indexPath];
if (!isLoadingNextPage)
{
[self fetchData];
}
}
return cell;
}
Loading Cell Code
-(UITableViewCell *) loadingCell :(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:nil];
cell.backgroundColor = [UIColor clearColor];
UIActivityIndicatorView *activityIndicatorView =[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicatorView.color = [UIColor blackColor];
activityIndicatorView.center = CGPointMake(self.tblView.center.x, cell.center.y);
[cell.contentView addSubview:activityIndicatorView];
[activityIndicatorView startAnimating];
cell.userInteractionEnabled = NO;
return cell;
}
Api call implementation
-(void)fetchData
{
isLoadingNextPage = YES;
if (currentPage==-1)
currentPage=0;
//API Call
{
DLog(#"API Call Response = %#",response);
isLoadingNextPage = NO;
if (response == nil)
{
hasNextPage=NO;
return;
}
if (success)
{
if (hasNextPage)
{
currentPage++;
}
[arrTableData addObjectsFromArray:response];
}
else
{
hasNextPage=NO;
}
//Reload tableview
}];
}
Alternative solution for this is
Use the SVPullToRefresh library in integrate infinite scrolling of it.
https://github.com/samvermette/SVPullToRefresh
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(self.comptabl.contentOffset.y >= (self.comptabl.contentSize.height - self.comptabl.bounds.size.height))
{
if(isPageRefreshing==NO){
isPageRefreshing=YES;
[appDelegate showIndicator:nil view1:self.view];
start=start+50;
[self makeRequest:start];
[self.comptabl reloadData];
NSLog(#"called %d",start);
}
}
}
I am using this method but at all time the value is increment with 50 ..how can i set limit to the value
In my project I need to implement the UITableview with some of the tableView cells are expandable and some of them are independent. If it is expandable cell need to indicate the '+' symbol.enter image description here. Can any one please help me out
I have created a small demo,
https://github.com/haripalwagh/ExpandableTableviewCell
Screenshot 1 : Before expanding a cell
Screenshot 2 : After expanding a cell
#interface ViewController ()
<UITableViewDataSource,
UITableViewDelegate>
{
UITableView *tblView;
NSArray *cell0SubMenuItemsArray;
BOOL isSection0Cell0Expanded;
}
#end
#implementation ViewController
# pragma mark - View Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
tblView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
tblView.backgroundColor = [UIColor clearColor];
tblView.delegate = self;
tblView.dataSource = self;
tblView.allowsSelection = YES;
tblView.scrollEnabled = YES;
tblView.alwaysBounceVertical = YES;
[self.view addSubview:tblView];
cell0SubMenuItemsArray = #[#"First Static Menu Item", #"Second Static Menu Item", #"Third Static Menu Item"];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.view setNeedsLayout];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self updateViewDimensions];
}
- (void)updateViewDimensions
{
tblView.frame = CGRectMake(0, 40, 320, 550);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
# pragma mark - UITableView Delegate and Datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
{
int cellCount = 2; // Default count - if not a single cell is expanded
if (isSection0Cell0Expanded)
{
cellCount += [cell0SubMenuItemsArray count];
}
return cellCount;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellId = #"CellId";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strCellId];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (indexPath.section == 0)
{
if (indexPath.row == 0)
{
cell.textLabel.text = #"Expandable Cell";
UIImageView *accessoryImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
if (isSection0Cell0Expanded) // Set accessory view according to cell state - EXPANDED / NOT EXPANDED
{
accessoryImageView.image = [UIImage imageNamed:#"Minus.png"];
cell.detailTextLabel.text = #"Status : Expanded";
}
else
{
accessoryImageView.image = [UIImage imageNamed:#"Plus.png"];
cell.detailTextLabel.text = #"Status : Not Expanded";
}
cell.accessoryView = accessoryImageView;
}
else
{
if (isSection0Cell0Expanded && [cell0SubMenuItemsArray count] >= indexPath.row) // Check Expanded status and do the necessary changes
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", [cell0SubMenuItemsArray objectAtIndex:indexPath.row - 1]];
}
else
{
cell.textLabel.text = #"Static Cell";
}
}
}
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
// Change status of a cell reload table
isSection0Cell0Expanded = !isSection0Cell0Expanded;
[tblView reloadData];
}
}
You have to manage like this for every expandable cell.
Hope this will help you..
Try this control: https://github.com/jonasman/JNExpandableTableView
It supports what you say. Tapping on a cell expands it.
In the source code below I am able to change my checkmark object value, but at the time of reload data in cellForRowAtIndexPath method it shows old data:
//TableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [self.tableData count];
}
//CellforRowAtIndexpath showing old table data
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Recipe *obj = nil;
obj = self.tableData[indexPath.row];
cell.textLabel.text = obj.name;
NSLog(#"Reload Data %#", obj.checkmark);
if ([obj.checkmark integerValue] == 1)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Recipe *recipe = nil;
recipe = [self.tableData objectAtIndex:indexPath.row];
if ([recipe.checkmark integerValue] == 1)
{
recipe.checkmark=#"0";
}
else
{
//recipe.checkmark=#"1";
for (int i=0; i<[self.tableData count]; i++) {
if (i==indexPath.row) {
recipe.checkmark=#"1";
}
else{
recipe.checkmark=#"0";
}
NSLog(#"PK ! %#", recipe.checkmark);
}
}
//[self.tableData addObject:recipe.checkmark];
[self.myTable reloadData];
[self.myTable reloadData];
}
The good news is normally this issue is in the cell for row logic, but it looks like you have that portion right. I believe the issue is in your cell for row logic because you are not updating tableData correctly. See extra comments below.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Recipe *recipe = nil;
recipe = [self.tableData objectAtIndex:indexPath.row];
if ([recipe.checkmark integerValue] == 1)
{
recipe.checkmark=#"0";
}
else
{
//This only gets called if current checked cell is already checked
for (int i=0; i<[self.tableData count]; i++) {
if (i==indexPath.row) {
recipe.checkmark=#"1";
}
else{
//This is still the recipe for the cell currently selected
recipe.checkmark=#"0";
}
NSLog(#"PK ! %#", recipe.checkmark);
}
}
//[self.tableData addObject:recipe.checkmark];
[self.myTable reloadData];
[self.myTable reloadData];
}
Something like this should fix your issue without changing too much of your code or structure.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Recipe *recipe = [self.tableData objectAtIndex:indexPath.row];
if ([recipe.checkmark integerValue] == 1)
{
recipe.checkmark=#"0";
}
else
{
recipe.checkmark=#"1";
}
//remove all old checkmarks
for (int i=0; i<[self.tableData count]; i++)
{
//Only update recipes that are not in this row
if (i!=indexPath.row)
{
recipe = [self.tableData objectAtIndex:i];
recipe.checkmark=#"0";
}
}
[self.myTable reloadData];
}
Another things to consider is instead of using a string that you are converting to an integer that is acting like a BOOL just change recipe's property checkmark to a BOOL. I hope that helps and good luck.
I have a UITableView and his datasource is an NSMutableArray declared in my interface:
#property (strong, nonatomic) NSMutableArray *arrElements;
Now I implemented a simple "load more" in this way:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height)
{
//only if i have others results i will call load more
if([self.items_amount integerValue] > self.arrElements.count) {
if(DEBUG_MODE == 1) {
NSLog(#"Load more");
}
//get start param from array size and call load more
NSNumber *start = [NSNumber numberWithInteger:([self.arrElements count]+1)];
NSArray *passParams = [NSArray arrayWithObjects:self.menuItem,start,[NSNumber numberWithInteger:NUM_RESULTS_FOR_PAGE], nil];
[self performSelector:#selector(loadMore:) withObject:passParams afterDelay:0.1];
}
}
}
and this is my loadMore method:
//load more elements
- (void)loadMore:(NSArray *)arrParams {
//(MenuItem *)menuItem startingFrom:(NSNumber *)start numResults:(NSNumber *)results;
MenuItem *menuItem = [arrParams objectAtIndex:0];
NSNumber *start = [arrParams objectAtIndex:1];
NSNumber *results = [arrParams objectAtIndex:2];
if(DEBUG_MODE == 1) {
NSLog(#"Before load more %lu", (unsigned long)[self.arrElements count]);
}
//call API and parse it
WebServicesClient *restClient = [[WebServicesClient alloc] init];
NSData *data = [restClient callWorkAPI:[menuItem pathAPI] inLanguage:[[NSLocale preferredLanguages] objectAtIndex:0] withLat:self.latitude withLng:self.longitude startingFrom:start numRows:results];
for(Work* work in [[restClient parseWorks:data] objectForKey:#"items"]) {
[self.arrElements addObject:work];
}
if(DEBUG_MODE == 1) {
NSLog(#"After load more %lu", (unsigned long)[self.arrElements count]);
}
[self.tableElem reloadData];
}
And this is my custom cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier;
CellIdentifier = #"HomeCell";
HomeCell *cell = (HomeCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell) {
cell = [[HomeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Work *work = (Work *)[[self arrElements] objectAtIndex:indexPath.row];
cell.backgroundColor = [UIColor clearColor];
cell.labelTitleItem.text = [work title];
cell.labelSubtitleItem.text = #"my category"
//if exists image
if([[work image] isKindOfClass:[NSString class]] && [[work image] length] > 0) {
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:[work image]]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageItem.image = [UIImage imageWithData: data];
});
});
} else {
//remove image setting height to 0
[cell.imageItem setFrame:CGRectMake(cell.imageItem.frame.origin.x, cell.imageItem.frame.origin.y, cell.imageItem.frame.size.width, 0)];
}
if([[work distance] isKindOfClass:[NSString class]]) {
[cell.imagePriority setBackgroundColor:[UIColor lightGrayColor]];
cell.labelDistanceItem.text = [self convertDistance:[work distance]];
cell.labelDistanceItem.textColor = [UIColor whiteColor];
} else {
//remove image setting height to 0
[cell.imagePriority setFrame:CGRectMake(cell.imagePriority.frame.origin.x, cell.imagePriority.frame.origin.y, cell.imagePriority.frame.size.width, 0)];
//remove label distance setting height to 0
[cell.labelSubtitleItem setFrame:CGRectMake(cell.labelSubtitleItem.frame.origin.x, cell.labelSubtitleItem.frame.origin.y, cell.labelSubtitleItem.frame.size.width, 0)];
}
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self arrElements] count];
}
Now the problem is that after reloadData i lose the text of a UILabel (my category) of my CustomCell
please, Any suggests?
I've had similar problems with TalbeViews. Try using the method
- (void) tableView:(UITableView *)tableView willDisplayCell:(RCGameTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
to add the elements that you want. Keep the cell initialization that you do at the beginning of cellForRowAtIndexPath, but then return the cell right after and set the background color, labels, images, etc. in the willDisplayCell delegate function I mentioned.
The working is simple. I have a collectionview in iOS. I am receiving number of items as to be selected. I want to show this as ON . Rest should be switched OFF. User interaction is disabled.
you can set it in below method but you have to set proper Code.
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
//stuff
if(indexPath.row %2 ==0) //replace this with your condtion.
{
cell.selected = YES;
cell.userInteractionEnabled = YES;
}
else
{
cell.selected = NO;
cell.userInteractionEnabled = NO;
}
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
loyalityCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
NSUserDefaults * userDefault = [NSUserDefaults standardUserDefaults];
NSString *userStamps = [userDefault objectForKey:#"stamps"];
for (int i=0; i<=userStamps.intValue; i++)
{
if (indexPath.row < userStamps.integerValue)
{
cell.stampImage.image = [UIImage imageNamed:#"stamphover.png"];
cell.selected= true;
cell.userInteractionEnabled= NO;
}
else
{
cell.stampImage.image= [UIImage imageNamed:#"stamp.png"];
cell.selected = true;
cell.userInteractionEnabled= NO;
}
}
return cell;
}