UITableView with customcell - ios

i am developing an iPhone app with tableview that act as a form with different sections. i also have 3 custom cell that contain Text Field, Segment Control and UISwitchView. my problem is that when i pressed on of the Switches or type some text in one of the textField, the same state of the Switch or text of the text Field reappear in different row and in different section.
Here is some images and part of my code to describe my problem:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger rows = 0;
switch (section) {
case 0:
rows = 5;
break;
case 1:
rows = 11;
break;
case 2:
rows = 9;
break;
default:
break;
}
return rows;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
// init cell
switch (indexPath.section) {
case 0:
if (indexPath.row>=0 && indexPath.row<=3)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"text_field_cell"];
}
else if (indexPath.row == 4)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"segment_cell"];
}
break;
case 1:
if (indexPath.row >=0 && indexPath.row <= 9)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"switch_cell"];
}
else if (indexPath.row == 10)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"text_field_cell"];
}
break;
case 2:
if (indexPath.row >=0 && indexPath.row <= 6)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"switch_cell"];
}
else if (indexPath.row >=7 && indexPath.row <=8)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"text_field_cell"];
}
break;
default:
break;
}
// init all text ..
return cell;
}

I would implement -tableView:willDisplayCell:forRowAtIndexPath: to set your cells to a correct state for each row.

Related

UITableViewCell is choppy when scrolled for Custom Table View Cell

I have a tableview that contains 3 different types of uitableview cell. And it is choppy when i scrolled down or up. I have tried many ways to not make it choppy but fail.
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
CD_Dates *dates = [self.cdMenuStream.dates objectAtIndex:indexPath.section];
MenuTableViewCell *tCell = [self.tableView dequeueReusableCellWithIdentifier:#"MenuTableViewCell" forIndexPath:indexPath];
switch ([self getRowTypeForIndexPath:indexPath]) {
case RowTypeMenu:
[tCell configMenuCell:dates.menu withAnimation:self.switchMenuAnimationFlag];
break;
case RowTypeAddon:
[tCell configAddonCell:dates.addon_menu withAnimation:self.switchMenuAnimationFlag];
break;
case RowTypeContent:
[tCell configContentCell:dates.content];
break;
default:
break;
}
tCell.delegate = self;
tCell.currentIndexPath = indexPath;
if (indexPath.section == 0 && indexPath.row == 0) {
tCell.csMarginTopTitleView.constant = 0;
}
[tCell setNeedsDisplay];
[tCell layoutIfNeeded];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
cell = tCell;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat heightRow = 0;
switch ([self getRowTypeForIndexPath:indexPath]) {
case RowTypeMenu:
heightRow = 477.6667;
break;
case RowTypeAddon:
heightRow = 283.6667;
break;
case RowTypeContent:
heightRow = 187.6667;
break;
default:
break;
}
if (heightRow == 0) {
return UITableViewAutomaticDimension;
}
if (indexPath.section == 0 && indexPath.row == 0) {
heightRow = heightRow - 22.5;
}
return heightRow;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(MenuTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat horizontalOffset = -17.5;
NSString *key = [NSString stringWithFormat:#"%zd %zd", indexPath.section, indexPath.row];
if ([self.contentOffsetDictionary valueForKey:key]) {
horizontalOffset = [self.contentOffsetDictionary[key] floatValue];
}
[cell setNeedsDisplay];
[cell.collectionView setContentOffset:CGPointMake(horizontalOffset, cell.collectionView.contentOffset.y)];
[cell layoutIfNeeded];
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat heightRow = 0;
switch ([self getRowTypeForIndexPath:indexPath]) {
case RowTypeMenu:
heightRow = 477.6667;
break;
case RowTypeAddon:
heightRow = 283.6667;
break;
case RowTypeContent:
heightRow = 187.6667;
break;
default:
break;
}
if (heightRow == 0) {
return UITableViewAutomaticDimension;
}
if (indexPath.section == 0 && indexPath.row == 0) {
heightRow = heightRow - 22.5;
}
return heightRow;
}
It is a tableview wrapped with a custom tableview cell, and that each custom tableview cell has a collection view. It is not choppy if i scroll the collection view in the custom tableview cell, but it is when i scroll the tableview. Is there any ways we can make it not choppy, thanks.
I think you should go with the sizing cell.
https://www.raywenderlich.com/129059/self-sizing-table-view-cells
Please try with this or share the cell's .xib files so that automatic sizing will be enabled.

Expand/Collapse table row when multiple number of sections in tableview

Here i am trying to create expand/collapse table row.it is working fine with this code in didSelectRowAtIndexPath only for 1 section:
if (selectedIndex == indexPath.row) {
selectedIndex = -1;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]withRowAnimation:UITableViewRowAnimationFade];
return;
}
//for table view collapse
if (selectedIndex != -1) {
NSIndexPath *prePath = [NSIndexPath indexPathForRow:selectedIndex inSection:0];
selectedIndex = (int)indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:prePath, nil]withRowAnimation:UITableViewRowAnimationFade];
}
//for non selection
selectedIndex = (int)indexPath.row;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]withRowAnimation:UITableViewRowAnimationFade];
through this code i can expand and collapse table row but if and only if for 1 section in table but when multiple section comes it is expanding each sections particular row.so when i click on section 0's 1st row it is going to open all section's 1st row.
How to get rid of this situation?
Tapping on particular section button you can change number of rows.
In section view you have added one button for all section which has common method while tapping.
In tapping method you have to just change bool variable value for particular section
ex.. if sender tag you initials with section number.
So For Section 0 button is taped then in tapping method
if sender.tag == 0
{
if section0tag
{
section0tag = false
}
else
{
section0tag = true
}
table.reload() ..//Which call number of rows at section data source method
}
For number of rowsatSection method data source method
if section == 0
{
if section0tag
{
return 5 //Expanding rows
}
else
{
return 0 //collapsing rows
}
}
Try this method just reload tableview (i.e rOne,rTwo, etc are the bool value):
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return rOne ? oneRoundType.count : 0 ;
}else if (section ==1) {
return rTwo ? twoRoundType.count : 0 ;
}else if (section ==2) {
return rThree ? threeRoundType.count : 0 ;
}else if (section ==3) {
return rFour ? fourRoundType.count : 0 ;
}else if (section ==4) {
return rFive ? fiveRoundType.count : 0 ;
}
return 0;
}
Please try below code:
Global declaration of sectionIndexToBeExpanded as int to check whether it is expanded or not
int sectionIndexToBeExpanded;
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//Assign value 100 to sectionIndexToBeExpanded, if you do not want row expanded
sectionIndexToBeExpanded = 100;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [yourArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (sectionIndexToBeExpanded==100) //If not expanded
{
return 1;
}
else if (sectionIndexToBeExpanded==section) //If section expand add one more row
{
return 2;
}
else
return 1;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row==0)
{
if (sectionIndexToBeExpanded==100) //If section not expanded set value of sectionIndexToBeExpanded to 100
{
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationRight];
sectionIndexToBeExpanded=(int)indexPath.section;
[tableView endUpdates];
}
else if (sectionIndexToBeExpanded==indexPath.section) // If Section is already expanded at indexpath then collapse ie. delete row
{
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:sectionIndexToBeExpanded]] withRowAnimation:UITableViewRowAnimationLeft];
sectionIndexToBeExpanded=100; //Set section to not expanded
[tableView endUpdates];
}
else //Expand section
{
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:sectionIndexToBeExpanded]] withRowAnimation:UITableViewRowAnimationLeft];
//set value of expanded section to sectionIndexToBeExpanded
sectionIndexToBeExpanded=(int)indexPath.section;
[tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationLeft];
[tableView endUpdates];
}
}
}
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}

Custom components to cells in Table

How do i add different componenets to different cells in a tableview. Please note that this is a static table and i have only 4 cells.
The first cell will have an UIImageView.
The other 3 cells will just have labels or textfieilds.
How can i add these components.
Note: This is a storyboard based application and i have added
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell;
if(indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.profImageView.image=[UIImage imageNamed:#"m.jpg"];
return cell;
}
else if(indexPath.row == 1)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell.lbl.text=#"Hey";
return cell;
}
else if(indexPath.row == 2)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
cell.lbl.text=#"Hey 2";
return cell;
}
return cell;
}
You are having 4 rows in your data source but you are only providing cell object for 3 rows. The last return statement will execute for indexPath.row==3 and you have not initialised it. Just initialise it for indexPath.row==3 and you are good to go.
MyTableViewCell *cell;
if(indexPath.row == 0)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.profImageView.image=[UIImage imageNamed:#"m.jpg"];
}
else if(indexPath.row == 1)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell.lbl.text=#"Hey";
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
cell.lbl.text=#"Hey 2";
}
return cell;
The reason that you don't give the default return value to your function and it asks for "If everything goes wrong what will i return?". So you may fix your codes like above and you can try to make like below with the switch - case.
TableViewCell *cell;
switch (indexPath.row) {
case 0:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.imageView.image=[UIImage imageNamed:#"m.jpg"];
}break;
case 1:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell.myLabel.text=#"Hey";
}break;
case 2:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
cell.myLabel.text=#"Hey 2";
}break;
default:{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell0"];
cell.imageView.image=[UIImage imageNamed:#"m.jpg"];
}
break;
}
return cell;
In above switch-case you may call which cell you want in default statement.

UITableView with multiple sections shows only one section

I have a problem which seems to be very simple. I have a UITableView in my APP. In numberOfSectionsInTableView: I set the count of sections to 2. However the tableView shows only the first section. I tried to make the two sections show same contents by writing same codes in both sections, but useless. Then I found a similar question here. But its correct answer is about frame and my layout is a very simple UITableViewController. At last I tried to add NSLog to the three methods. The result is: For case section 1, numberOfSectionsInTableView: and numberOfRowsInSection: are called but cellForRowAtIndex isn't called. I wonder how to explain this.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
int count;
switch (section) {
case 0:
count = [_objectArray count];
break;
case 1:
NSLog(#"section called"); // This line is logged
count = 1;
default:
count = 0;
break;
}
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myCellIdentifier";
static NSString *basicCellIdentifier = #"myBasicCellIdentifier";
switch ([indexPath section]) {
case 0: {
TableViewStoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
// Configure the cell...
int theIndex = [indexPath row];
MyObject *theObj = [_objectArray objectAtIndex:theIndex];
cell.object = theObj;
return cell;
break;
}
case 1: {
NSLog(#"cell called"); //this line isn't logged
for (int i = 0; i < 50; i++) {
NSLog(#"hahaha");
}
MyBasicViewStoryCell *cell = [tableView dequeueReusableCellWithIdentifier:basicCellIdentifier forIndexPath:indexPath];
return cell;
break;
}
default: {
for (int i = 0; i < 50; i++) {
NSLog(#"hahaha1");
}
return nil;
break;
}
}
}
Put break in switch case. You missed break in case 1: so the default will also execute. Thus the count become zero count = 0. Since numberOfRowsInSection: returns zero, cellForRowAtIndexPath: will not call. So put break in case 1: of numberOfRowsInSection:
switch (section) {
case 0:
count = [_objectArray count];
break;
case 1:
NSLog(#"section called"); // This line is logged
count = 1;
break; // Here
default:
count = 0;
break;
}
You don't have a break after you set the count for section 1 and it falls through and is set to zero.
case 1:
NSLog(#"section called"); // This line is logged
count = 1;
break; // always put break!
cellForRowAtIndexPath won't be called if numberOfRowsInSection is not returning a value that is >=1.

Cell hidden property [tableView]

I have section:1 has 11 rows. I set height like this
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) return 350;
else if (indexPath.section == 1) {
return 150;
}
else return 0;
}
if I set cell.hidden = YES; how can I remove the cell because if cell.hidden = YES it will be show space but I don't want that space I want if the cell is hidden directly remove from the secrion:1
or if I can set height for every hidden cells for 0.0
Thanks
EDIT
there is no NSArray for tableView it is customized like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) { return 1; }
else if (section == 1) {
int retype = [type intValue];
if (retype == 1 || retype == 5 || retype == 10) {
return 0;
}
else if (retype == 11) { return 9; }
else if (retype == 14) { return 4; }
else {
return 11;
}
}
else return 0;
}
and for the cell configure like this
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
int truef = [*nsstring* intValue];
if (indexPath.section == 1) {
if (indexPath.row == 0) {
if (truef == 0) {
cell.hidden = YES;
}
else {
cell.titleLabel.text = #"True";
}
}
}
EDIT 2
This the error after use deleteRowsAtIndexPaths
reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (11) must be equal to the number of rows contained in that section before the update (11), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out)
You don't need to hide cell. The appropriate way here is to remove this cell from your dataSource and remove it from table view via
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
EDIT
Well... you will agree with me that "magical numbers" which you are using is not good way.
I see the following solution here: you put all your numbers which you return in
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
into instance variables, like
#property (assign, nonatomic) numberOfRowsInSection0;
than you can decrease this variable and remove the LAST row. In you situation you will be able remove only last row from table view.
Conclusion: the solution above just a hack which will allow you to remove only last row in your table. You have to review you code again and change logic in order to use array or any other storage. The table view assumes that you have some data source, but you don't, that is the core of you problem.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if(cell.hidden) { return 0.0f; }

Resources