I have a project which uses Storyboards. I have a UITableView with Static cells and Group style.
I need to change the section text in one section depending on which selection is made in a segmented control (in another section)
I have found some solutions which indicate that you should use override this method:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
and trigger an update by calling:
[[self tableView]reloadSections:[NSIndexSet indexSetWithIndex:SectionToChange] withRowAnimation:UITableViewRowAnimationFade];
The problem is when I call reloadSections then all the rows and cells in the section in question get deleted. The text updates correctly thought but with this unwanted side effect.
I think I found the answer here: Changing UITableView section header without tableView:titleForHeaderInSection
It may not be very elegant but it seams to work.
I can trigger an update to only the section header with none of the unwanted side effects by calling:
[self.tableView headerViewForSection:1].textLabel.text = [self tableView:self.tableView titleForHeaderInSection:1];
So the only thing needed is to implement:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == 1){
if (self.segmentX.selectedSegmentIndex == 0) // or some condition
return #"Header one";
else
return #"Header two";
}
return nil;
}
If you have implemented these functions then removing them should fix your problem:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{ if (section == 0)
{
lbl.text = #"abc";
}
if (section == 2)
{
lbl.text = #"2ndsectionbeigns";
}
return headerview;
}
Related
I need to keep my first cell always located at top of tableview when i move others cell.I spent a lot of time and many ways button i haven't figure out that how to solve this problem.
This is my code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...do something to custom first cell design from xib file
//...do some thing to custom normal cells(cells at below of first cell)
[firstcell setEditing:NO animated:YES];
firstcell.userInteractionEnabled=NO;
if (indexPath.row==0)
{
return firstcell;
}
else
{
return cell;
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) // Don't move the first row
return NO;
return YES;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
// i just change datasource for tableview at here
}
And there is my tableview when I move cell (normal cell).
I wanna keep first cell (blue cell) always be at top and not be interact by others cell.
You need to implement one more delegate method:
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
if (proposedDestinationIndexPath.row == 0) {
// Don't allow a row to be moved to the first row position
return [NSIndexPath indexPathForRow:1 inSection:0];
} else {
return proposedDestinationIndexPath;
}
}
This code assume you only have one section in your table view.
The point of this method is to tell the table view that if the proposed destination for the row being moved isn't appropriate, the returned value should be used. As written here, any attempt to move a row to the top will result in it being moved just below the top row.
I am new to coding and have just started on working on a new app. I have been stuck for a few days searching for answers on how to remove null headers in a table header.
This is my code at the moment:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view=[DetailGroupHeader loadInstanceFromNib];
NSDictionary *category = [self.categories objectAtIndex:section];
if ([[self.restaurant objectForKey:#"restaurant_id"] isEqual:[category objectForKey:#"restaurant_id"]]) {
DetailGroupHeader *headerView=(DetailGroupHeader *)view;
headerView.lblTitle.text=[category objectForKey:#"maincatename"];
headerView.btnReveal.indexPath=[NSIndexPath indexPathForRow:0 inSection:section];
}
return view;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return self.categories.count;
}
At the top of -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section I am initiating the names of the headers, and this part is working perfectly fine.
However when I get to the next function -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView, to count the number of headers I receive null values, how can I get rid of the null values in the header?
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view=[DetailGroupHeader loadInstanceFromNib];
NSDictionary *category = [self.categories objectAtIndex:section];
if ([[self.restaurant objectForKey:#"restaurant_id"] isEqual:[category objectForKey:#"restaurant_id"]]) {
DetailGroupHeader *headerView = (DetailGroupHeader *)view;
NSString *maincateName = [category objectForKey:#"maincatename"];
if ([maincateName isEqual:[NSNull null]]) {
maincateName = #"";
}
headerView.lblTitle.text = maincateName;
headerView.btnReveal.indexPath = [NSIndexPath indexPathForRow:0 inSection:section];
}
return view;
}
I believe you are making some really basic mistakes. As I can see you are only showing those rows which have [[self.restaurant objectForKey:#"restaurant_id"] isEqual:[category objectForKey:#"restaurant_id"]] condition true. But you are returning numberOfSectionsInTableView, count of complete categories array as self.categories.count
I will suggest you to check:
Calculate count of header where condition [[self.restaurant objectForKey:#"restaurant_id"] isEqual:[category objectForKey:#"restaurant_id"]] satisfies
Check if the condition you are working with really have it's existence, (print log or set break point)
That's all I can say for now. If problem persist, add log print of your self.restaurant dictionary and self.categories array.
I am following an iOS tutorial and my code is supposed to be correct, but I am getting an error which is not shown at the original tutorial code.
These are the concerning methods:
-(BOOL)tableview:(UITableView *)tableView canCollapseSection:(NSInteger)section {
if (section >0) return YES;
return NO;
}
And here the piece of code supposed to be correct, but throws an error:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView)
{
return [self.searchResults count];
}
else {
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
.../...
The error is shown at line
if ([self tableView:tableView canCollapseSection:section])
And this is the error message:
No visible #interface for 'ToDoItemsTableViewController' declares the selector 'tableView:canCollapseSection:'
Is there any visible error in the code?...
in your method you are calling tableView but it should be tableview. small 'V'
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
tableView : V should be capital, please check after -(BOOL):tableview part
Declare
-(BOOL)tableview:(UITableView *)tableView canCollapseSection:(NSInteger)section
in your .h file.
Also make sure that, you typed it correctly (any spelling mistake can also cause the issue).
You just need to declare your method
-(BOOL)tableview:(UITableView *)tableView canCollapseSection:(NSInteger)section
in yourViewController.h file.
I am implementing swipe to delete feature on one of my table that uses custom table view cells. The issue I am facing is when I tap on "Delete" button, I see a weird transition while cell is being removed.
Below is my code in "commitEditingStyle" and also see the attached screenshot I captured while row is being removed.
PS: I have tried with all types of row removal animation styles but no luck.
- (void)tableView:(UITableView *)iTableView commitEditingStyle:(UITableViewCellEditingStyle)iEditingStyle forRowAtIndexPath:(NSIndexPath *)iIndexPath {
if (iEditingStyle == UITableViewCellEditingStyleDelete && iTableView == self.temporaryCartTable) {
if (self.temporaryCartTable.frame.size.height == kMyAppCartTableViewExpandedHeight) {
[self.temporaryCartTable beginUpdates];
[self.temporaryCartTable deleteRowsAtIndexPaths:[NSArray arrayWithObjects: iIndexPath, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
MyAppCartInfo *aMyAppCartInfo = [self cart];
if (([[aMyAppCartInfo.tempProducts allKeys] count] > iIndexPath.row) && [aMyAppCartInfo.tempProducts containsObjectForKey:[[aMyAppCartInfo.tempProducts allKeys] objectAtIndex:iIndexPath.row]]) {
[aMyAppCartInfo.tempProducts removeObjectForKey:[[aMyAppCartInfo.tempProducts allKeys] objectAtIndex:iIndexPath.row]];
}
[self.temporaryCartTable endUpdates];
}
}
}
- (BOOL)tableView:(UITableView *)iTableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return (iTableView == self.temporaryCartTable) ? YES : NO;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)iTableView editingStyleForRowAtIndexPath:(NSIndexPath *)iIndexPath {
return UITableViewCellEditingStyleDelete;
}
- (CGFloat)tableView:(UITableView *)iTableView heightForRowAtIndexPath:(NSIndexPath *)iIndexPath {
if (iTableView == self.temporaryCartTable) {
if (self.isTempCartCell)
return 92.0;
else
return 58.0;
} else {
return 58.0;
}
}
Add the following method implementation to your UITableViewDelegate
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
Use [self.temporaryCartTable setRowHeight:xxx] instead of using the delegate rowHeightAtIndexPath. After the row is deleted and there is no other rows in the table, the delegate will not called and your table view's row height will be retrieved by its property (hence the default height). Plus, using this method from the delegate affects the performance.
If anyone else is having this, the problem in my case was heightForRowAtIndexPath: When cells have dynamic size delete animation behaves strange. In my case the solution was to use a different approach and not spend time investigating. But you can test it and see results. Assign a fixed height for cells:
self.tableView.rowHeight = Constant;
comment out heightForRowAtIndexPath:. And animations should be ok now.
I know this is not the solution but may still help someone.
I need to create a grouped uitableview that includes some sections and possibly different cell types in each sections.
I am trying to create something like old foursquare app, user page (includes 'leaderboard', 'friend suggestions', 'friends', 'stats', 'most explored categories' ... sections).
I am fairly new to ios programming, so that view may not be a grouped uitableview.
What I especially stuck is creating different cells for sections, and finding out which cells are clicked.
My data source will be 2 different NSArray* that consists of different data types, that's why I need different custom cells.
Since you have two different sets of data and you need to display both in different sections, you have to split the data source methods into two.
Basically, choose which dataset you want to be first and off you go.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section)return secondArray.count;
//Essentially, if statements evaluate TRUE and move forward if the inside is 1 or greater (TRUE == 1)
return firstArray.count;
//If the first if statement return hits, then the code will never reach this statement which turns this into a lighter if else statement
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section)
{
//do stuff with second array and choose cell type x
}
else
{
//do stuff with first array and choose cell type y
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get the cell with: UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(indexPath.section)
{
//perform action for second dataset
}
else
{
//perform action for first dataset
}
}
For headers, you can use either of these methods and just keep the same type of styling as above:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
You can create multiple custom subclasses of UITableViewCell, and in the tableView:cellForRowAtIndexPath: method for your UITableViewDataSource, you can use if-statements to determine what type of cell to use.
For example, here's a rough outline of what I might do:
-(UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//First, determine what type of object we're showing
if (indexPath.section == 0) {
//Create and return this cell.
} else if (indexPath.section == 1) {
//Create and return this cell.
}...
}
Here's how you'd implement numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return [firstSectionArray count];
} else if (section == 1) {
return [secondSectionArray count];
} ...
}
For didSelectRowAtIndexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
ObjectSelected *objectSelected = [firstArray objectAtIndex:indexPath.row];
//Now you've got the object, so push a view controller:
DetailViewController *dvc = [[DetailViewController alloc] init];
dvc.objectSelected = objectSelected;
[self.navigationController pushViewController:dvc];
} else if (indexPath.section == 1) {
//Same thing, just call [secondArray objectAtIndex:indexPath.row] instead!
}
}