Expanding and collapsing tableView sections iOS? - ios

I am able to expand and collapse the tableView sections successfully however I am not able to do it for individual sections so far.So all the sections collapse or expand at the same time, which is because I call [tableView reloadData] .So How can I expand or collapse a particular section?
Here is how I am doing it currently.
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.2];
headerLabel.text = [menuCategoryArray objectAtIndex:section];
headerLabel.frame = CGRectMake(5, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(headerClicked:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
}
-(void)headerClicked:(UIGestureRecognizer*)sender
{
if (!isShowingList) {
isShowingList=YES;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
}else{
isShowingList=NO;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (isShowingList) {
return [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
}else{
return 0;
}
return 0;
}

First take isShowingList as
#property (nonatomic, strong) NSMutableArray *isShowingList;
And for identifying previously opened section you need another property
#property (nonatomic, assign) NSInteger openSectionIndex;
when you have the data initialized, isShowingList in you case, initialize isShowingList array before reloading table
self.isShowingList = [NSMutableArray array];
if (jsonArray && [jsonArray valueForKey:#"menus"] && [[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"]) {
for (int i = 0; i < [[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] count]; i++) {
[self.isShowingList addObject:[NSNumber numberWithBool:NO]];
}
}
and initialize openSectionIndex in viewDidLoad() like this
self.openSectionIndex = NSNotFound;
and your code should be changed like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([[self.isShowingList objectAtIndex:section] boolValue]) {
return [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
} else {
return 0;
}
return 0;
}
-(void)headerClicked:(UIGestureRecognizer*)sender {
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
if ([[self.isShowingList objectAtIndex:lbl.tag] boolValue]) {
[self closeSection:lbl.tag];
} else {
[self openSection:lbl.tag];
}
}
//methods for expanding and collapsing sections
- (void)openSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:YES]];
NSInteger countOfRowsToInsert = [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.menuTableView reloadSections:[NSIndexSet indexSetWithIndex:previousOpenSectionIndex] withRowAnimation:UITableViewRowAnimationNone];
});
[self.isShowingList replaceObjectAtIndex:previousOpenSectionIndex withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:previousOpenSectionIndex] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
// Apply the updates.
[self.menuTableView beginUpdates];
[self.menuTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView endUpdates];
self.openSectionIndex = section;
}
- (void)closeSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [self.menuTableView numberOfRowsInSection:section];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
}

You really would be better off looking at using a 'tableView update block'. Please take a look at this viewController for an answer I posted very recently. The updateBlock allows you to manipulate some variable or other which affects the dataSource, and instruct the table to add/remove rows/sections in order to reflect that change. Note that when you call the endUpdates method the table must not conflict with the model or you'll get an exception.
#import "ViewController.h"
//dont worry, the header is empty except for import <UIKit/UIKit.h>, this is a subclass on UIViewController
#interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) UITableView *tableView;
#end
#implementation ViewController
{
//ivars
BOOL sectionIsOpen[4]; //we will use this BOOL array to keep track of the open/closed state for each section. Obviously I have the number of sections fixed at 4 here, but you could make a more dynamic array with malloc() if neccesary..
}
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tv = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tv.dataSource = self;
tv.delegate = self;
[self.view addSubview:tv];
self.tableView = tv;
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - UITableViewDataSource
-(NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{
return 4;
}
-(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ((sectionIsOpen[section]) ? [self numberOfRowsInSection:section] : 0);
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//put your switch() here...
return [NSString stringWithFormat:#"I am section %i", (int)section ];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellId = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];
}
//etc etc decorate your cell...
cell.textLabel.text = [NSString stringWithFormat:#"cell %i / %i", (int)indexPath.section, (int)indexPath.row ];
return cell;
}
#pragma mark - UITableViewDelegate
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
const CGRect fr = CGRectMake(0, 0, 320.0, 40.0 );
UIButton *btn = [[UIButton alloc]initWithFrame:fr];
[btn setTitle:[self tableView:tableView titleForHeaderInSection:section] forState:UIControlStateNormal ];
[btn setTag:section];
[btn addTarget:self action:#selector(sectionOpenToggle:) forControlEvents:UIControlEventTouchUpInside];
// add an image, colour etc if you like
return btn;
}
#pragma mark - tableViewHelpers
//the number of rows in sectionX when it is open...
-(NSInteger )numberOfRowsInSection:(NSInteger )section{
//get your count from your model
return section + 1;
}
//opening/closing a section
-(void )setSection:(NSInteger )section toOpen:(BOOL )open{
if (open != sectionIsOpen[section]) {
//build an array of indexPath objects
NSMutableArray *indxPths = [NSMutableArray array];
for (NSInteger row = 0; row < [self numberOfRowsInSection:section]; row ++) {
[indxPths addObject: [NSIndexPath indexPathForRow:row inSection:section ]
];
}
[self.tableView beginUpdates];
if (open) {
[self.tableView insertRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
//nb there is a large ENUM of tableViewRowAnimation types to experiment with..
}else{
[self.tableView deleteRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
}
sectionIsOpen[section] = open;
[self.tableView endUpdates];
}
}
-(void )sectionOpenToggle:(id )sender{
[self setSection:[sender tag] toOpen: !sectionIsOpen[[sender tag]] ];
}
// open/close all sections.
-(void )setAllSectionsOpen:(BOOL )open{
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView]; section ++) {
[self setSection:section toOpen:open];
}
}
//these two for your convenience, hook up to navbar items etc..
-(IBAction)openAllSections:(id)sender{
[self setAllSectionsOpen:YES];
}
-(IBAction)closeAllSections:(id)sender{
[self setAllSectionsOpen:NO];
}
#end

Related

How to apply multiple arrays in expandable tableview in ios

Hi i have tried to apply multiple arrays in expandable tableview.
but when i run my code it's showing exception.
exception:'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (4) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out)
how to solve this exception (or) any other example is available please suggest me.
please help me.
My Code:
.m file
#import "ExpandableListviewWithServices.h"
#interface ExpandableListviewWithServices (){
BackGroundPostServiceClass3 * back;
NSMutableArray *arrayForBool,*totalListOfArray,*respArray;
NSArray *sectionTitleArray;
UITableView *tableList;
}
#end
#implementation ExpandableListviewWithServices
- (void)viewDidLoad {
[super viewDidLoad];
tableList = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
tableList.translatesAutoresizingMaskIntoConstraints = NO;
tableList.dataSource=self;
tableList.delegate=self;
tableList.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tableList.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
tableList.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
[tableList registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
tableList.estimatedRowHeight = 44.0;
tableList.rowHeight = UITableViewAutomaticDimension;
[self.view addSubview:tableList];
NSDictionary * views = NSDictionaryOfVariableBindings(tableList);
NSArray * horizentalConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[tableList]-0-|" options:0 metrics:nil views:views];
NSArray * verticalConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[tableList]-0-|"options:0 metrics:nil views:views];
[self.view addConstraints:horizentalConstraint];
[self.view addConstraints:verticalConstraint];
[self initialization];
}
-(void)initialization
{
arrayForBool=[[NSMutableArray alloc]init];
sectionTitleArray=[[NSArray alloc]initWithObjects:
#"Apple",
#"Strawberry",
#"Grapes",
#"Orange",
#"Banana",
nil];
NSArray *new0=[[NSArray alloc]initWithObjects:#"Apple", #"Strawberry",#"Grapes",#"Orange", nil];
NSArray *new1=[[NSArray alloc]initWithObjects:#"Apple1", #"Strawberry1",#"Grapes1",#"Orange1"#"Orange1", nil];
NSArray *new2=[[NSArray alloc]initWithObjects:#"Apple2", #"Strawberry2",#"Grapes2",#"Orange2", nil];
NSArray *new3=[[NSArray alloc]initWithObjects:#"Apple3", #"Strawberry3",#"Grapes3",#"Orange3",#"Orange3", nil];
NSArray *new4=[[NSArray alloc]initWithObjects:#"Apple4", #"Strawberry4",#"Grapes4",#"Grapes4", nil];
totalListOfArray=[[NSMutableArray alloc]init];
[totalListOfArray addObject:new0];
[totalListOfArray addObject:new1];
[totalListOfArray addObject:new2];
[totalListOfArray addObject:new3];
[totalListOfArray addObject:new4];
for (int i=0; i<[sectionTitleArray count]; i++) {
[arrayForBool addObject:[NSNumber numberWithBool:NO]];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([[arrayForBool objectAtIndex:section] boolValue]) {
return [respArray count];
}
else
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell2";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
BOOL manyCells = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
// /********** If the section supposed to be closed *******************/
if(!manyCells)
{
cell.backgroundColor=[UIColor clearColor];
cell.textLabel.text=#"";
}
/********** If the section supposed to be Opened *******************/
else
{
cell.textLabel.text=[NSString stringWithFormat:#"%#",[respArray objectAtIndex:indexPath.row]];
cell.textLabel.font=[UIFont systemFontOfSize:15.0f];
cell.backgroundColor=[UIColor whiteColor];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
}
cell.textLabel.textColor=[UIColor blackColor];
/********** Add a custom Separator with cell *******************/
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 40, tableList.frame.size.width, 1)];
separatorLineView.backgroundColor = [UIColor blackColor];
[cell.contentView addSubview:separatorLineView];
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sectionTitleArray count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/*************** Close the section, once the data is selected ***********************************/
[arrayForBool replaceObjectAtIndex:indexPath.section withObject:[NSNumber numberWithBool:NO]];
[tableList reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[arrayForBool objectAtIndex:indexPath.section] boolValue]) {
return 40;
}
return 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 80;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 15;
}
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView *sectionView1=[[UIView alloc]initWithFrame:CGRectMake(0, 0, tableView.frame.size.width,40)];
sectionView1.backgroundColor = [UIColor whiteColor];
return sectionView1;
}
#pragma mark - Creating View for TableView Section
//# #e0e0eb place this color
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerview = [[UIView alloc] init];
headerview.backgroundColor = [UIColor lightGrayColor];
headerview.frame = CGRectMake(0, 0, tableView.frame.size.width, 80);
headerview.tag=section;
UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(10, 20, tableList.frame.size.width, 25)];
label1.text = #"Hi";
[headerview addSubview:label1];
UITapGestureRecognizer *headerTapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sectionHeaderTapped:)];
[headerview addGestureRecognizer:headerTapped];
return headerview;
}
#pragma mark - Table header gesture tapped
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:gestureRecognizer.view.tag];
NSLog(#" index ---->>> %ld",(long)indexPath.section);
for (int i=0; i<[sectionTitleArray count]; i++){
if (indexPath.section == i) {
BOOL collapsed = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
for (int i=0; i<[sectionTitleArray count]; i++) {
if (indexPath.section==i) {
[arrayForBool replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:!collapsed]];
}else{
[arrayForBool replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:collapsed]];
}
}
[self selectedOption:(int)indexPath.section];
[tableList reloadSections:[NSIndexSet indexSetWithIndex:gestureRecognizer.view.tag] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
}
-(NSMutableArray *)selectedOption:(int)mySelectedItemData{
NSLog(#"%d",mySelectedItemData);
NSMutableArray *arrayValue=[[NSMutableArray alloc]init];
respArray=[[NSMutableArray alloc]init];
NSLog(#"%#",[totalListOfArray objectAtIndex:mySelectedItemData]);
NSLog(#"%d",[[totalListOfArray objectAtIndex:mySelectedItemData] count]);
for (int i=0; i< [[totalListOfArray objectAtIndex:mySelectedItemData]count]; i++) {
[arrayValue addObject:[[totalListOfArray objectAtIndex:mySelectedItemData] objectAtIndex:i]];
//[arrayValue addObject:[itemsArray objectAtIndex:mySelectedItemData]];
NSLog(#"array value is =======> %#",arrayValue);
[arrayForBool addObject:[NSNumber numberWithBool:NO]];
}
respArray=[arrayValue mutableCopy];
NSLog(#"respArray items are =====> %#",respArray);
return arrayValue;
}
I am placing the below functions with code change which you have done. See, understand and replace the function with your code.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *arrayCount = [totalListOfArray objectAtIndex:section];
return [arrayCount count];
}
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:gestureRecognizer.view.tag];
NSLog(#" index ---->>> %ld",(long)indexPath.section);
for (int i=0; i<[sectionTitleArray count]; i++){
if (indexPath.section == i) {
BOOL collapsed = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
for (int i=0; i<[sectionTitleArray count]; i++) {
if (indexPath.section==i) {
if (collapsed == NO) {
[arrayForBool replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:YES]];
}
else{
[arrayForBool replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:NO]];
}
}else{
NSLog(#"%#",arrayForBool);
[arrayForBool replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:NO]];
}
}
[self selectedOption:(int)indexPath.section];
}
}
}
-(NSMutableArray *)selectedOption:(int)mySelectedItemData{
NSLog(#"%d",mySelectedItemData);
NSMutableArray *arrayValue=[[NSMutableArray alloc]init];
respArray=[[NSMutableArray alloc]init];
NSLog(#"%#",[totalListOfArray objectAtIndex:mySelectedItemData]);
NSLog(#"%lu",(unsigned long)[[totalListOfArray objectAtIndex:mySelectedItemData] count]);
for (int i=0; i< [[totalListOfArray objectAtIndex:mySelectedItemData]count]; i++) {
[arrayValue addObject:[[totalListOfArray objectAtIndex:mySelectedItemData] objectAtIndex:i]];
NSLog(#"array value is =======> %#",arrayValue);
}
respArray=[arrayValue mutableCopy];
[tableList reloadSections:[NSIndexSet indexSetWithIndex:mySelectedItemData] withRowAnimation:UITableViewRowAnimationAutomatic];
NSLog(#"respArray items are =====> %#",respArray);
return arrayValue;
}

How to create two custom tableview cell within single tableview using iOS Storyboard?

I am trying to create accordion tableview with seperate tableviewCell within single tableview using iOS storyboard. below I have added my test code. Please help me for solving issues.
My Source:
Tableview Methods Index data's I am getting from property list
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.itemsInTable count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *Title= [[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Name"];
return [self createCellWithTitle:Title image:[[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Image name"] indexPath:indexPath];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dic=[self.itemsInTable objectAtIndex:indexPath.row];
if([dic valueForKey:#"SubItems"])
{
NSArray *arr=[dic valueForKey:#"SubItems"];
BOOL isTableExpanded=NO;
for(NSDictionary *subitems in arr )
{
NSInteger index=[self.itemsInTable indexOfObjectIdenticalTo:subitems];
isTableExpanded=(index>0 && index!=NSIntegerMax);
if(isTableExpanded) break;
}
if(isTableExpanded)
{
[self CollapseRows:arr];
}
else
{
NSUInteger count=indexPath.row+1;
NSMutableArray *arrCells=[NSMutableArray array];
for(NSDictionary *dInner in arr )
{
[arrCells addObject:[NSIndexPath indexPathForRow:count inSection:0]];
[self.itemsInTable insertObject:dInner atIndex:count++];
}
[self.main_tableview insertRowsAtIndexPaths:arrCells withRowAnimation:UITableViewRowAnimationNone];
}
}
}
CollapseRow Process
-(void)CollapseRows:(NSArray*)ar
{
for(NSDictionary *dInner in ar )
{
NSUInteger indexToRemove=[self.itemsInTable indexOfObjectIdenticalTo:dInner];
NSArray *arInner=[dInner valueForKey:#"SubItems"];
if(arInner && [arInner count]>0)
{
[self CollapseRows:arInner];
}
if([self.itemsInTable indexOfObjectIdenticalTo:dInner]!=NSNotFound)
{
[self.itemsInTable removeObjectIdenticalTo:dInner];
[self.main_tableview deleteRowsAtIndexPaths:[NSArray arrayWithObject:
[NSIndexPath indexPathForRow:indexToRemove inSection:0]
]
withRowAnimation:UITableViewRowAnimationNone];
}
}
}
Tableview UI. Same UI appearing Into child tableview cell also. I need to show seperate UI for parent and child tableview cell
- (UITableViewCell*)createCellWithTitle:(NSString *)title image:(UIImage *)image indexPath:(NSIndexPath*)indexPath
{
NSString *CellIdentifier_one = #"Cell_One";
cell_one = [self.main_tableview dequeueReusableCellWithIdentifier:CellIdentifier_one];
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor colorWithRed:54/255.0f green:169/255.0f blue:224/255.0f alpha:0.40f];
cell_one.backgroundColor = [UIColor colorWithRed:54/255.0f green:169/255.0f blue:224/255.0f alpha:0.25f];
cell_one.selectedBackgroundView = bgView;
cell_one.titlelbl.text = title;
cell_one.titlelbl.textColor = [UIColor blackColor];
return cell_one;
}
well you have indexPath. YOU must know which cell to use for which indexPath.
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id cell;
if(indexPath.row==0) {
cell = [self createCell];
}
else {
cell = [self createOtherCell];
}
return cell;
}

Switch example from UITableViewController to UITableView

I am relatively new in iOS, I have found an example of accordion table view that I need. But the thing is that example is TableViewController and I need to implement TableView inside viewController. Can you please help me. What I have tried to do is create tableView, declare it in the h file as
#property (strong, nonatomic) IBOutlet UITableView *MyTb;
and then change all appearances of self.tableView to self.MyTb but it did not work, oh also changed
AccordionTableViewController : UITableViewController
to
AccordionTableViewController : UIViewController
So here is the original code, please help me and provide some guiadance to it, thanks.
h file:
#import <UIKit/UIKit.h>
#interface AccordionTableViewController : UITableViewController {
NSArray *topItems;
NSMutableArray *subItems; // array of arrays
int currentExpandedIndex;
}
#end
m file:
#import "AccordionTableViewController.h"
#define NUM_TOP_ITEMS 20
#define NUM_SUBITEMS 6
#implementation AccordionTableViewController
- (id)init {
self = [super init];
if (self) {
topItems = [[NSArray alloc] initWithArray:[self topLevelItems]];
subItems = [NSMutableArray new];
currentExpandedIndex = -1;
for (int i = 0; i < [topItems count]; i++) {
[subItems addObject:[self subItems]];
}
}
return self;
}
#pragma mark - Data generators
- (NSArray *)topLevelItems {
NSMutableArray *items = [NSMutableArray array];
for (int i = 0; i < NUM_TOP_ITEMS; i++) {
[items addObject:[NSString stringWithFormat:#"Item %d", i + 1]];
}
return items;
}
- (NSArray *)subItems {
NSMutableArray *items = [NSMutableArray array];
int numItems = arc4random() % NUM_SUBITEMS + 2;
for (int i = 0; i < numItems; i++) {
[items addObject:[NSString stringWithFormat:#"SubItem %d", i + 1]];
}
return items;
}
#pragma mark - View management
- (void)viewDidLoad {
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [topItems count] + ((currentExpandedIndex > -1) ? [[subItems objectAtIndex:currentExpandedIndex] count] : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ParentCellIdentifier = #"ParentCell";
static NSString *ChildCellIdentifier = #"ChildCell";
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
UITableViewCell *cell;
if (isChild) {
cell = [tableView dequeueReusableCellWithIdentifier:ChildCellIdentifier];
}
else {
cell = [tableView dequeueReusableCellWithIdentifier:ParentCellIdentifier];
}
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ParentCellIdentifier] autorelease];
}
if (isChild) {
cell.detailTextLabel.text = [[subItems objectAtIndex:currentExpandedIndex] objectAtIndex:indexPath.row - currentExpandedIndex - 1];
}
else {
int topIndex = (currentExpandedIndex > -1 && indexPath.row > currentExpandedIndex)
? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count]
: indexPath.row;
cell.textLabel.text = [topItems objectAtIndex:topIndex];
cell.detailTextLabel.text = #"";
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
if (isChild) {
NSLog(#"A child was tapped, do what you will with it");
return;
}
[self.tableView beginUpdates];
if (currentExpandedIndex == indexPath.row) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
currentExpandedIndex = -1;
}
else {
BOOL shouldCollapse = currentExpandedIndex > -1;
if (shouldCollapse) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
}
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
[self expandItemAtIndex:currentExpandedIndex];
}
[self.tableView endUpdates];
}
- (void)expandItemAtIndex:(int)index
{
NSMutableArray *indexPaths = [NSMutableArray new];
NSArray *currentSubItems = [subItems objectAtIndex:index];
int insertPos = index + 1;
for (int i = 0; i < [currentSubItems count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:insertPos++ inSection:0]];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
//[indexPaths release];
}
- (void)collapseSubItemsAtIndex:(int)index
{
NSMutableArray *indexPaths = [NSMutableArray new];
for (int i = index + 1; i <= index + [[subItems objectAtIndex:index] count]; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
//[indexPaths release];
}
- (void)dealloc
{
[topItems release];
[subItems release];
[super dealloc];
}
#end
You must set your view controller as delegate and datasource of your tableview:
#interface AccordionTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
in your header file and in viewDidLoad:
-(void)viewDidLoad {
[super viewDidLoad];
self.MyTb.delegate = self;
self.MyTb.dataSource = self;
}
Or you can set the datasource and delegate in Storyboard. You must also make sure you have connected the table view to MyTb IBOutlet in storyboard.

SKSTableView Scrolling Issue

I am currently using this custom/ expandable tableview code called SKSTableView which can be found at Here
Here's the issue, when I fill the table with over 10 rows, the UI Locks up and the scrolling begins to be extremely laggy. I can't seem to be able to track down the issue, but I am thinking it has something to do with reusing the cell.
Here's some code that will hopefully help.
-SKSTableView hasn't changed
-Below is the implementation in the actual file /Home Screen of app
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Bar *bar = [bars objectAtIndex:indexPath.row];
NSArray *friendsAtBar = (NSArray*)bar.friends;
static NSString *cellIdentifier = #"SKSTableViewCell";
SKSTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell){//If no cell, create a new one
cell = [[SKSTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
UIColor *cellBackgroundColor = [UIColor colorWithWhite:( 30/255.0) alpha:1.0];
UIColor *cellTextColor = [UIColor colorWithWhite:0.80 alpha:1.0];
UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 73, 320, 2)];
bottomLine.backgroundColor = [UIColor colorWithWhite:( 50/255.0) alpha:1.0];
cell.nameLabel.textColor = cellTextColor;
cell.friendsLabel.textColor = cellTextColor;
cell.backgroundColor = cellBackgroundColor;
cell.selectionBanner.backgroundColor = cellBackgroundColor;
[cell addSubview:bottomLine];
[cell.goingButton addTarget:self
action:#selector(goingButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.nameLabel.frame = nameStartFrame;
}
if (friendsAtBar != nil && friendsAtBar.count != 0)
cell.isExpandable = YES;
else
cell.isExpandable = NO;
cell.nameLabel.text = bar.name;
//cell.userInteractionEnabled = YES;
if (friendsAtBar.count == 1) // If only 1 friend is going, say friend, if more than 1 friend is going say friends
cell.friendsLabel.text = [NSString stringWithFormat:#"%lu friend going",(unsigned long)friendsAtBar.count];
else if (friendsAtBar.count > 1)
cell.friendsLabel.text = [NSString stringWithFormat:#"%lu friends going",(unsigned long)friendsAtBar.count];
else {
cell.friendsLabel.text = #"";
//cell.nameLabel.frame = CGRectMake(20, 26, 200, 23);
}
//cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.tag = indexPath.row;
[self deselectGoingButton:cell.goingButton];
if ([bar.objectID isEqualToString:[currentUser objectForKey:#"currentBarID"]] && [self under15Hours:[currentUser objectForKey:#"barTimeStamp"]])
{
goingToBarID = bar.objectID; // HERE
//NSLog(#"goingToBarID from cell: %#",goingToBarID);
selectedGoingToButton = cell.goingButton;
[self selectGoingButton:cell.goingButton];
}
cell.goingButton.tag = indexPath.row;
cell.selectionBanner.tag = indexPath.row;
return cell;
}
#pragma mark - TableView - Subrow
- (NSInteger)tableView:(SKSTableView *)tableView numberOfSubRowsAtIndexPath:(NSIndexPath *)indexPath {
if (bars != nil && bars.count != 0) {
Bar *bar = [bars objectAtIndex:indexPath.row];
return bar.friends.count;
}
else
return 0;
} // PARSE IMPACTED
- (UITableViewCell *)tableView:(UITableView *)tableView cellForSubRowAtIndexPath:(NSIndexPath *)indexPath {
//NSMutableDictionary *bar = [bars objectAtIndex:indexPath.row];
Bar *bar = [bars objectAtIndex:indexPath.row];
NSArray *friendsAtBar = (NSArray*)bar.friends;
//UIColor *cellBackgroundColor = [UIColor colorWithWhite:( 20/255.0) alpha:1.0];
//UIColor *cellTextColor = [UIColor colorWithWhite:0.85 alpha:1.0];
UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 73, 320, 2)];
bottomLine.backgroundColor = [UIColor colorWithWhite:( 50/255.0) alpha:1.0];
static NSString *cellIdentifier = #"FriendsGoingCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UIView *cellView;
UILabel *nameLabel;
UILabel *usernameLabel;
UIButton *callButton;
UIButton *textButton;
if (!cell){//If no cell, make a new one
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cellView = [self createSubRowView];
nameLabel = [cellView.subviews objectAtIndex:1];
usernameLabel = [cellView.subviews objectAtIndex:2];
usernameLabel.textColor = [UIColor colorWithWhite:0.7 alpha:1.0];
callButton = [cellView.subviews objectAtIndex:3];
textButton = [cellView.subviews objectAtIndex:4];
[cell addSubview:cellView];
[cell addSubview:bottomLine];
}
//cell.backgroundColor = cellBackgroundColor;
cell.tag = 2;
//PFUser *user = [friendsAtBar objectAtIndex:indexPath.subRow-1];
Friend *user = [friendsAtBar objectAtIndex:indexPath.subRow-1];
//UILabel *nameLabel = [cellView.subviews objectAtIndex:1];
//nameLabel.text = [[friendsAtBar objectAtIndex:indexPath.subRow-1] objectForKey:#"username"];
nameLabel.text = [NSString stringWithFormat:#"%#",user.compositeName];
//nameLabel.textColor = cellTextColor;
// UILabel *usernameLabel = [cellView.subviews objectAtIndex:2];
usernameLabel.text = user.userName;
//UIButton *callButton = [cellView.subviews objectAtIndex:3];
callButton.tag = indexPath.subRow-1;
//UIButton *textButton = [cellView.subviews objectAtIndex:4];
textButton.tag = indexPath.subRow-1;
return cell;
}
[self createSubView]
- (UIView *)createSubRowView {
UIView *cellView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, [rowHeight floatValue])];
UIColor *fontColor = [UIColor colorWithWhite:0.85 alpha:1.0];
UIView* bgview = [[UIView alloc] initWithFrame:cellView.frame];
bgview.backgroundColor = [UIColor colorWithWhite:0.15 alpha:1.0];
[cellView addSubview:bgview];
UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 16, 180, 23)];
nameLabel.textColor = fontColor;
nameLabel.font = [UIFont boldSystemFontOfSize:17];
[cellView addSubview:nameLabel];
UILabel *goingTimeStampLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 41, 180, 16)];
goingTimeStampLabel.textColor = fontColor;
goingTimeStampLabel.font = [UIFont systemFontOfSize:13];
[cellView addSubview:goingTimeStampLabel];
CGFloat x = 200;
CGFloat width = 55;
CGFloat height = [rowHeight floatValue];
CGFloat y = ([rowHeight floatValue] - height)/2;
UIButton *callButton = [[UIButton alloc] initWithFrame:CGRectMake(x, y, width, height)];
UIImage *callIcon = [UIImage imageNamed:#"call.png"];
[callButton setImage:callIcon forState:UIControlStateNormal];
[callButton addTarget:self
action:#selector(clickedCallButton:)
forControlEvents:UIControlEventTouchUpInside];
[cellView addSubview:callButton];
UIButton *textButton = [[UIButton alloc] initWithFrame:CGRectMake(x+width, y, width, height)];
UIImage *textIcon = [UIImage imageNamed:#"text.png"];
[textButton setImage:textIcon forState:UIControlStateNormal];
[textButton addTarget:self
action:#selector(clickedTextButton:)
forControlEvents:UIControlEventTouchUpInside];
[cellView addSubview:textButton];
return cellView;
}
SKSTableView.m
#import "SKSTableView.h"
#import "SKSTableViewCell.h"
#import "SKSTableViewCellIndicator.h"
#import <objc/runtime.h>
#pragma mark - NSArray (SKSTableView)
#interface NSMutableArray (SKSTableView)
- (void)initiateObjectsForCapacity:(NSInteger)numItems;
#end
#implementation NSMutableArray (SKSTableView)
- (void)initiateObjectsForCapacity:(NSInteger)numItems
{
for (NSInteger index = [self count]; index < numItems; index++) {
NSMutableArray *array = [NSMutableArray array];
[self addObject:array];
}
}
#end
#pragma mark - SKSTableView
#interface SKSTableView () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) NSMutableArray *expandedIndexPaths;
#property (nonatomic, strong) NSMutableDictionary *expandableCells;
#end
#implementation SKSTableView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_shouldExpandOnlyOneCell = NO;
}
return self;
}
- (void)setSKSTableViewDelegate:(id<SKSTableViewDelegate>)SKSTableViewDelegate
{
self.dataSource = self;
self.delegate = self;
[self setSeparatorColor:[UIColor colorWithRed:236.0/255.0 green:236.0/255.0 blue:236.0/255.0 alpha:1.0]];
if (SKSTableViewDelegate)
_SKSTableViewDelegate = SKSTableViewDelegate;
}
- (void)setSeparatorColor:(UIColor *)separatorColor
{
[super setSeparatorColor:separatorColor];
[SKSTableViewCellIndicator setIndicatorColor:separatorColor];
}
- (NSMutableArray *)expandedIndexPaths
{
if (!_expandedIndexPaths)
_expandedIndexPaths = [NSMutableArray array];
return _expandedIndexPaths;
}
- (NSMutableDictionary *)expandableCells
{
if (!_expandableCells)
_expandableCells = [NSMutableDictionary dictionary];
return _expandableCells;
}
#pragma mark - UITableViewDataSource
#pragma mark - Required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_SKSTableViewDelegate tableView:tableView numberOfRowsInSection:section] + [[[self expandedIndexPaths] objectAtIndex:section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (![self.expandedIndexPaths[indexPath.section] containsObject:indexPath]) {
NSIndexPath *tempIndexPath = [self correspondingIndexPathForRowAtIndexPath:indexPath];
SKSTableViewCell *cell = (SKSTableViewCell *)[_SKSTableViewDelegate tableView:tableView cellForRowAtIndexPath:tempIndexPath];
if ([[self.expandableCells allKeys] containsObject:tempIndexPath])
[cell setIsExpanded:[[self.expandableCells objectForKey:tempIndexPath] boolValue]];
[cell setSeparatorInset:UIEdgeInsetsZero];
if (cell.isExpandable) {
[self.expandableCells setObject:[NSNumber numberWithBool:[cell isExpanded]]
forKey:indexPath];
UIButton *expandableButton = (UIButton *)cell.accessoryView;
[expandableButton addTarget:tableView
action:#selector(expandableButtonTouched:event:)
forControlEvents:UIControlEventTouchUpInside];
if (cell.isExpanded) {
cell.accessoryView.transform = CGAffineTransformMakeRotation(M_PI);
} else {
if ([cell containsIndicatorView])
[cell removeIndicatorView];
}
} else {
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell removeIndicatorView];
cell.accessoryView = nil;
}
return cell;
} else {
NSIndexPath *indexPathForSubrow = [self correspondingIndexPathForSubRowAtIndexPath:indexPath];
UITableViewCell *cell = [_SKSTableViewDelegate tableView:(SKSTableView *)tableView cellForSubRowAtIndexPath:indexPathForSubrow];
cell.backgroundView = nil;
cell.backgroundColor = [self separatorColor];
cell.indentationLevel = 2;
return cell;
}
}
#pragma mark - Optional
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if ([_SKSTableViewDelegate respondsToSelector:#selector(numberOfSectionsInTableView:)]) {
NSInteger numberOfSections = [_SKSTableViewDelegate numberOfSectionsInTableView:tableView];
if ([self.expandedIndexPaths count] != numberOfSections)
[self.expandedIndexPaths initiateObjectsForCapacity:numberOfSections];
return numberOfSections;
}
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if ([_SKSTableViewDelegate respondsToSelector:#selector(tableView:titleForHeaderInSection:)])
return [_SKSTableViewDelegate tableView:tableView titleForHeaderInSection:section];
return nil;
}
#pragma mark - UITableViewDelegate
#pragma mark - Optional
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([_SKSTableViewDelegate respondsToSelector:#selector(tableView:didSelectRowAtIndexPath:)])
[_SKSTableViewDelegate tableView:tableView didSelectRowAtIndexPath:indexPath];
if ([_SKSTableViewDelegate respondsToSelector:#selector(tableView:didDeselectRowAtIndexPath:)])
[_SKSTableViewDelegate tableView:tableView didDeselectRowAtIndexPath:indexPath];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
SKSTableViewCell *cell = (SKSTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[SKSTableViewCell class]] && cell.isExpandable) {
cell.isExpanded = !cell.isExpanded;
NSIndexPath *_indexPath = indexPath;
if (cell.isExpanded && self.shouldExpandOnlyOneCell) {
_indexPath = [self correspondingIndexPathForRowAtIndexPath:indexPath];
[self collapseCurrentlyExpandedIndexPaths];
}
NSInteger numberOfSubRows = [self numberOfSubRowsAtIndexPath:_indexPath];
NSMutableArray *indexPaths = [NSMutableArray array];
NSInteger row = _indexPath.row;
NSInteger section = _indexPath.section;
for (NSInteger index = 1; index <= numberOfSubRows; index++) {
NSIndexPath *expIndexPath = [NSIndexPath indexPathForRow:row+index inSection:section];
[indexPaths addObject:expIndexPath];
}
if (cell.isExpanded) {
[self setIsExpanded:YES forCellAtIndexPath:_indexPath];
[self insertExpandedIndexPaths:indexPaths forSection:_indexPath.section];
} else {
[self setIsExpanded:NO forCellAtIndexPath:_indexPath];
[self removeExpandedIndexPaths:indexPaths forSection:_indexPath.section];
}
[self accessoryViewAnimationForCell:cell];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
if ([_SKSTableViewDelegate respondsToSelector:#selector(tableView:accessoryButtonTappedForRowWithIndexPath:)])
[_SKSTableViewDelegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
[self.delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
CGFloat height = 0;
if ([_SKSTableViewDelegate respondsToSelector:#selector(tableView:heightForHeaderInSection:)])
height = [_SKSTableViewDelegate tableView:tableView heightForHeaderInSection:section];
return height;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] init];
if ([_SKSTableViewDelegate respondsToSelector:#selector(tableView:viewForHeaderInSection:)])
view = [_SKSTableViewDelegate tableView:tableView viewForHeaderInSection:section];
return view;
}
#pragma mark - SKSTableViewUtils
- (IBAction)expandableButtonTouched:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self];
NSIndexPath *indexPath = [self indexPathForRowAtPoint:currentTouchPosition];
if (indexPath)
[self tableView:self accessoryButtonTappedForRowWithIndexPath:indexPath];
}
- (NSInteger)numberOfSubRowsAtIndexPath:(NSIndexPath *)indexPath
{
return [_SKSTableViewDelegate tableView:self numberOfSubRowsAtIndexPath:[self correspondingIndexPathForRowAtIndexPath:indexPath]];
}
- (NSIndexPath *)correspondingIndexPathForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index = 0;
NSInteger row = 0;
while (index < indexPath.row) {
NSIndexPath *tempIndexPath = [self correspondingIndexPathForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:indexPath.section]];
BOOL isExpanded = [[self.expandableCells allKeys] containsObject:tempIndexPath] ? [[self.expandableCells objectForKey:tempIndexPath] boolValue] : NO;
if (isExpanded) {
NSInteger numberOfExpandedRows = [_SKSTableViewDelegate tableView:self numberOfSubRowsAtIndexPath:tempIndexPath];
index += (numberOfExpandedRows + 1);
} else
index++;
row++;
}
return [NSIndexPath indexPathForRow:row inSection:indexPath.section];
}
- (NSIndexPath *)correspondingIndexPathForSubRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index = 0;
NSInteger row = 0;
NSInteger subrow = 0;
while (1) {
NSIndexPath *tempIndexPath = [self correspondingIndexPathForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:indexPath.section]];
BOOL isExpanded = [[self.expandableCells allKeys] containsObject:tempIndexPath] ? [[self.expandableCells objectForKey:tempIndexPath] boolValue] : NO;
if (isExpanded) {
NSInteger numberOfExpandedRows = [_SKSTableViewDelegate tableView:self numberOfSubRowsAtIndexPath:tempIndexPath];
if ((indexPath.row - index) <= numberOfExpandedRows) {
subrow = indexPath.row - index;
break;
}
index += (numberOfExpandedRows + 1);
} else
index++;
row++;
}
return [NSIndexPath indexPathForSubRow:subrow inRow:row inSection:indexPath.section];
}
- (void)setIsExpanded:(BOOL)isExpanded forCellAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *correspondingIndexPath = [self correspondingIndexPathForRowAtIndexPath:indexPath];
[self.expandableCells setObject:[NSNumber numberWithBool:isExpanded] forKey:correspondingIndexPath];
}
- (void)insertExpandedIndexPaths:(NSArray *)indexPaths forSection:(NSInteger)section
{
NSIndexPath *firstIndexPathToExpand = indexPaths[0];
NSIndexPath *firstIndexPathExpanded = nil;
if ([self.expandedIndexPaths[section] count] > 0) firstIndexPathExpanded = self.expandedIndexPaths[section][0];
__block NSMutableArray *array = [NSMutableArray array];
if (firstIndexPathExpanded && firstIndexPathToExpand.section == firstIndexPathExpanded.section && firstIndexPathToExpand.row < firstIndexPathExpanded.row) {
[self.expandedIndexPaths[section] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSIndexPath *updated = [NSIndexPath indexPathForRow:([obj row] + [indexPaths count])
inSection:[obj section]];
[array addObject:updated];
}];
[array addObjectsFromArray:indexPaths];
self.expandedIndexPaths[section] = array;
} else {
[self.expandedIndexPaths[section] addObjectsFromArray:indexPaths];
}
[self sortExpandedIndexPathsForSection:section];
// Reload TableView
[self insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
}
- (void)removeExpandedIndexPaths:(NSArray *)indexPaths forSection:(NSInteger)section
{
NSUInteger index = [self.expandedIndexPaths[section] indexOfObject:indexPaths[0]];
[self.expandedIndexPaths[section] removeObjectsInArray:indexPaths];
if (index == 0) {
__block NSMutableArray *array = [NSMutableArray array];
[self.expandedIndexPaths[section] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSIndexPath *updated = [NSIndexPath indexPathForRow:([obj row] - [indexPaths count])
inSection:[obj section]];
[array addObject:updated];
}];
self.expandedIndexPaths[section] = array;
}
[self sortExpandedIndexPathsForSection:section];
// Reload Tableview
[self deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
}
- (void)collapseCurrentlyExpandedIndexPaths
{
NSArray *expandedCells = [self.expandableCells allKeysForObject:[NSNumber numberWithBool:YES]];
if (expandedCells.count > 0) {
NSIndexPath *indexPath = [expandedCells firstObject];
[self.expandableCells setObject:[NSNumber numberWithBool:NO] forKey:indexPath];
[self removeExpandedIndexPaths:[self.expandedIndexPaths[indexPath.section] copy] forSection:indexPath.section];
SKSTableViewCell *cell = (SKSTableViewCell *)[self cellForRowAtIndexPath:indexPath];
cell.isExpanded = NO;
[self accessoryViewAnimationForCell:cell];
}
}
- (void)sortExpandedIndexPathsForSection:(NSInteger)section
{
[self.expandedIndexPaths[section] sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if ([obj1 section] < [obj2 section])
return (NSComparisonResult)NSOrderedAscending;
else if ([obj1 section] > [obj2 section])
return (NSComparisonResult)NSOrderedDescending;
else {
if ([obj1 row] < [obj2 row])
return (NSComparisonResult)NSOrderedAscending;
else
return (NSComparisonResult)NSOrderedDescending;
}
}];
}
- (void)accessoryViewAnimationForCell:(SKSTableViewCell *)cell
{
__block SKSTableViewCell *_cell = cell;
[UIView animateWithDuration:0.2 animations:^{
if (_cell.isExpanded) {
_cell.accessoryView.transform = CGAffineTransformMakeRotation(M_PI);
} else {
_cell.accessoryView.transform = CGAffineTransformMakeRotation(0);
}
} completion:^(BOOL finished) {
if (!_cell.isExpanded)
[_cell removeIndicatorView];
}];
}
#end
#pragma mark - NSIndexPath (SKSTableView)
static void *SubRowObjectKey;
#implementation NSIndexPath (SKSTableView)
#dynamic subRow;
- (NSInteger)subRow
{
id subRowObj = objc_getAssociatedObject(self, SubRowObjectKey);
return [subRowObj integerValue];
}
- (void)setSubRow:(NSInteger)subRow
{
id subRowObj = [NSNumber numberWithInteger:subRow];
objc_setAssociatedObject(self, SubRowObjectKey, subRowObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
+ (NSIndexPath *)indexPathForSubRow:(NSInteger)subrow inRow:(NSInteger)row inSection:(NSInteger)section
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
indexPath.subRow = subrow;
return indexPath;
}
#end

How can I update/reload/refresh a section header view in a UITableView?

I'm willing to change a specific header view of my UITableView when I click a row.
I've read all posts about it yet. I tried "reloadData", "setNeedDisplay", "reloadSections:withRowAnimation:", and several others ideas... there is nothing to do. My header view either doesn't update or it does weird things like updating only when I move the table view (which is not what I'm willing to achieve).
My code looks like this for now (regarding the UITableView delegates methods):
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
if(tableView==_storeTableView){
return [_storeDataArray count];
} else {
return 1;
}
}
-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section {
if(tableView==_storeTableView){
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:section];
if (!headerModel.headerView) {
NSString *shelfName = headerModel.shelf;
headerModel.headerView = [[[HouraStoreHeaderView alloc] initWithFrame:CGRectMake(0.0, 0.0, _storeTableView.bounds.size.width, 80) title:shelfName section:section subheaderNumber:([headerModel.openedSubHeaders count]-1) delegate:self] autorelease];
}
return headerModel.headerView;
} else {
return nil;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView==_storeTableView){
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:section];
NSDictionary *myDict = _storeDataDict;
for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
}
NSInteger numberOfRowsInSection = [[myDict allKeys] count];
return headerModel.open ? numberOfRowsInSection : 0;
} else if(tableView==_searchTableView){
return [_resultArray count];
} else {
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if(tableView==_storeTableView){
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
NSDictionary *myDict = _storeDataDict;
for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
}
cell.accessoryView=[[[HouraStoreCellView alloc] initWithFrame:CGRectMake(0.0, 0.0, _storeTableView.bounds.size.width, 50) title:[[myDict allKeys] objectAtIndex:indexPath.row]] autorelease];
return cell;
} else if (tableView==_searchTableView) {
cell.textLabel.text = [_resultArray objectAtIndex:indexPath.row];
return cell;
} else {
return cell;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:section];
NSInteger height = 59.0 + ([headerModel.openedSubHeaders count]-1)*41.0;
return height;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableView==_storeTableView){
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
NSDictionary *myDict = _storeDataDict;
for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
}
if ([[myDict objectForKey:[[myDict allKeys] objectAtIndex:indexPath.row]] isKindOfClass:[NSDictionary class]]) {
[self cellOpened:indexPath];
} else {
[_activityIndicatorView startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(_listProductsFoundedFinished:)
name:HouraSearchProductsDone
object:nil];
NSString *searchString = [[myDict allKeys] objectAtIndex:indexPath.row];
searchString = [searchString stringByReplacingOccurrencesOfString:#"\"" withString:#"\\u0022"];
[_singleton.util beginSearchProducts:searchString context:#"2"];
}
} else if(tableView==_searchTableView){
_searchBar.text = [_resultArray objectAtIndex:indexPath.row];
[_searchBar resignFirstResponder];
[_activityIndicatorView startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(_listProductsFoundedFinished:)
name:HouraSearchProductsDone
object:nil];
[_singleton.util beginSearchProducts:_searchBar.text context:#"2"];
}
}
-(void)headerView:(HouraStoreHeaderView*)headerView headerOpened:(NSInteger)headerOpened {
if (self.openSectionIndex!=NSNotFound) {
[self closeAllHeaders];
}
//[self closeAllHeaders];
HouraStoreHeaderModel *headerModel =nil;
headerModel = [self.headerInfoArray objectAtIndex:headerOpened];
headerModel.open = YES;
headerModel.headerView.disclosureButton.selected = YES;
NSDictionary *myDict = _storeDataDict;
for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
}
NSInteger countOfRowsToInsert = [[myDict allKeys] count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:headerOpened]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
HouraStoreHeaderModel *previousHeaderModel = [self.headerInfoArray objectAtIndex:previousOpenSectionIndex];
previousHeaderModel.open = NO;
previousHeaderModel.headerView.disclosureButton.selected = NO;
[previousHeaderModel.headerView toggleOpenWithUserAction:NO];
NSInteger countOfRowsToDelete = [[[_storeDataDict objectForKey:previousHeaderModel.shelf ] allKeys] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
UITableViewRowAnimation insertAnimation;
UITableViewRowAnimation deleteAnimation;
if (previousOpenSectionIndex == NSNotFound || headerOpened < previousOpenSectionIndex) {
insertAnimation = UITableViewRowAnimationTop;
deleteAnimation = UITableViewRowAnimationBottom;
} else {
insertAnimation = UITableViewRowAnimationBottom;
deleteAnimation = UITableViewRowAnimationTop;
}
[_storeTableView beginUpdates];
[_storeTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[_storeTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];
[_storeTableView endUpdates];
self.openSectionIndex = headerOpened;
}
-(void)headerView:(HouraStoreHeaderView*)headerView headerClosed:(NSInteger)headerClosed {
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:headerClosed];
headerModel.open = NO;
headerModel.headerView.disclosureButton.selected = NO;
[headerModel cleanOpenedSubHeaders];
[self.headerInfoArray replaceObjectAtIndex:headerClosed withObject:headerModel];
NSInteger countOfRowsToDelete = [_storeTableView numberOfRowsInSection:headerClosed];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:headerClosed]];
}
[_storeTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
}
-(void)cellOpened:(NSIndexPath*)indexPath {
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
[self headerView:headerModel.headerView headerClosed:indexPath.section];
[headerModel addOpenedSubHeaders:[[[_storeDataDict objectForKey:headerModel.shelf] allKeys] objectAtIndex:indexPath.row]];
[self.headerInfoArray replaceObjectAtIndex:indexPath.section withObject:headerModel];
headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
[self headerView:headerModel.headerView headerOpened:indexPath.section];
}
-(void)closeAllHeaders {
for (NSInteger i = 0; i < [self.headerInfoArray count]; i++) {
HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:i];
[self headerView:headerModel.headerView headerClosed:i];
}
}
What I'd like to do is, when I click a row, the section header update so it contains a new button with the row text. Then I dismiss the row and reload new datas in the section rows. I managed to handle the rows perfectly. But I can't find a way to get this header view updated.
Thx for any idea.
You just change it directly. I created an instance variable in the header file for a label that I will put in the header's view I'll create:
#interface MainViewController : UITableViewController {
// creating my datasource array instance variable
NSArray *_items;
// this is the label I will add to the header view when I create it
UILabel *_headerLabel;
}
#end
And in my tableView when they select a row I call a function that simply changes the text on the label:
#implementation MainViewController
- (id)init {
self = [super initWithStyle:UITableViewStyleGrouped];
/ filling my datasource with test strings
_items = #[#"one", #"two"];
return self;
}
- (void)changeHeaderLabel:(NSString *)newLabel {
// when this function gets called and is passed a string, I will simply
// set the text on the label to the new string and viola!
_headerLabel.text = newLabel;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// this table will only have a single section for demo purposes
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// return the count of my datasource array
return _items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// attempt to create a cell by reusing one with a given identifier
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
// if I wasn't able to reuse one
if (cell == nil) {
// create one from scratch with that identifier
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
// now simply set the text on the cell from my data source array of strings
cell.textLabel.text = _items[indexPath.row];
// and return the cell
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// deselect the row so the cell automatically fades out after selection
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// here you could do one of two things, either get a reference to the cell itself,
// and then get the value stored in it's textLabel
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *newHeaderTitleString = selectedCell.textLabel.text;
// OR you can get it right from your datasource
NSString *newHeaderTitleString = _items[indexPath.row];
// then just call the above function with the string as the single param
[self changeHeaderLabel:newHeaderTitleString];
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
// here I just create a view that will span the whole frame and is an arbitrary height
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 80)];
// set the background color to clear
headerView.backgroundColor = [UIColor clearColor];
// then I initialize my instance variable with a frame that's centered in the view
// for aesthetic purposes
_headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.view.frame.size.width - 10, 80)];
// then I set the text color, add an autoresizing mask so if the view rotates
// it still remains centered properly, set the text to some starting value,
// and add it to the headerView I previously created
_headerLabel.textColor = [UIColor darkGrayColor];
_headerLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_headerLabel.text = #"Before";
[headerView addSubview:_headerLabel];
// then I return the headerView
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
// return an arbitrary height here for testing
return 80;
}
That results in the following:
If you have any questions let me know! This is just a quick example to demonstrate it, but you may want to customize the view in a different way altogether. This should at least solve your problem and give you a starting point to work from.
Have you tried reloadRowsAtIndexPaths:withRowAnimation: where you set the row property of the NSIndexPath passed in as NSNotFound? So reloading just the header of section 3, for instance would look like
NSIndexPath * headerIndexPath = [NSIndexPath indexPathForRow: NSNotFound section:3];
[self.tableView reloadRowsAtIndexPaths:#[headerIndexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
I guarantee nothing, but I'm pretty sure it used to work before, because I used it a couple of times.
But even if it works, it's still a hack that might get broken by Apple any time.
edit
Ok, never mind. I tried this with iOS 7 in Xcode 5 and for some reason, even with NSNotFound as the row number, it still reloads the whole sections (with all its cells). So this does not work any more, damn.

Resources