How to remove cell from static UITableView created in Storyboard - ios

This should be easy, but I'm having trouble.
I have a static UITableView with a cell that I would like to remove programmatically if it's not needed.
I have a IBOutlet for it
IBOutlet UITableViewCell * cell15;
And I can remove it by calling
cell15.hidden = true;
This hides it, but leaves a blank space where the cell used to be and I can't get rid of it.
Perhaps a hack would be to change the height of it to 0?
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:indexPath
{
//what would I put here?
}
Thanks so much!

You can't really deal with this in the datasource since with static tables you don't even implement the datasource methods. The height is the way to go.
Try this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell == cell15 && cell15ShouldBeHidden) //BOOL saying cell should be hidden
return 0.0;
else
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
Update
It appears that, under autolayout, this may not be the best solution. There is an alternative answer here which may help.

You can use tableView:willDisplayCell and tableView:heightForRowAtIndexPath with the cell identifier to show/hide static tableview cells, but yo must implement heightForRowAtIndexPath referring to super, not to self. These two methods work fine for me:
(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell.reuseIdentifier.description isEqualToString:#"cellCelda1"]) {
[cell setHidden:YES];
}
}
and
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if ([cell.reuseIdentifier.description isEqualToString:#"cellCelda1"]) {
return 0;
}
return cell.frame.size.height;
}

Depending on how your table is supposed to work, in your data source you can implement tableView:numberOfRowsInSection: to return 0 rows for the section based on your necessary logic.
Updated for your comment:
The section parameter will be populated by iOS when your implementation is called so all you need is a switch to handle the section that has the row you ant removed/hidden. Example below:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
switch(section) {
case 0: // first section of your table, change for your situation
return 0;
default:
return 0;
}
}

It for only constant cell
-(void)tableViewSearchPeopleCellHide:(BOOL)hide{
searchCellShouldBeHidden=hide;
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
cell.hidden=hide;
self.searchPeople.hidden=hide;//UILabel
[self.tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (searchCellShouldBeHidden) //BOOL saying cell should be hidden
return 0.0;
else
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

The first thing you can do is tag the cell from storyboard which you want to hide.
Put some standard number which you can identify.
Add this code.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (cell.tag==10) { //I have put 10 for some static cell.
cell.hidden=YES;
return 0;
}
cell.hidden = NO;
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

Set the cell you want to hide to hidden somewhere in your code. Add this code: (If your cell has different row height, then you need to override more functions)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rowCount=0;
for ( int row=0; row<[super tableView:tableView numberOfRowsInSection:section]; ++row){
NSIndexPath* path=[NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell* cell=[super tableView:tableView cellForRowAtIndexPath:path];
if (!cell.hidden){
++rowCount;
}
}
return rowCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int realRow=-1;
for ( int row=0; row<[super tableView:tableView numberOfRowsInSection:indexPath.section]; ++row){
NSIndexPath* path=[NSIndexPath indexPathForRow:row inSection:indexPath.section];
UITableViewCell* cell=[super tableView:tableView cellForRowAtIndexPath:path];
if (!cell.hidden){
++realRow;
}
if (realRow==indexPath.row)
return cell;
}
return nil;
}

Use index path to identify the cell in tableview height delegate and return 0
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if someCondition {
if indexPath.row == 1 || indexPath.row == 2 || indexPath.row == 3 {
return 0
}
}else{
if indexPath.row == 4 {
return 0
}
}
return super.tableView(tableView, heightForRowAt: indexPath)
}

Related

Issue While Finding Height of UITableViewCell

I am calculating height of Cell programatically in heightForRowAtIndexPath-
My complete method is:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id cell = [self.tableView dequeueReusableCellWithIdentifier:kCellID];
if([cell isKindOfClass:[Custom class]])
{
return 100;
}
else
{
return 20;
}
}
My app takes 3-5 sec to Show the ViewController. Although cellForRowAtIndexPath is called and I can show the logs in Console.
But My ViewController not loaded.
When just return the height using this code app works fine:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 100;
}
I don't know that is the issue with this line:
id cell = [self.tableView dequeueReusableCellWithIdentifier:kCellID];
What I am missing in this issue?
You have some logic in the cellForRowAtIndexPath: method that determines what type of cell that row should be. Add that logic into the heightForRowAtIndexPath: method to determine the what the height of each row should be.
Your this line is wrong
id cell = [self.tableView dequeueReusableCellWithIdentifier:kCellID];
it will force your cell to reuse.
Use
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id cell=[tableView cellForRowAtIndexPath:indexPath];
if([cell isKindOfClass:[CustomCellClass class]])
{
return 100;
}
else
{
return 20;
}
}

How to check if selected cell got reselected

I have a custom UITableViewCell, and I it expands on selection. What I want to do is make the cells height go back to normal (44), if the cell that was selected was reselected. Here is my code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath isEqual:self.selectedCell] && ![[tableView indexPathForSelectedRow] isEqual:indexPath]) {
return 100;
}
return 44;
}
The code works fine, but it seems to be ignoring the 2nd term in the if statement. Apparently I'm doing it wrong. Is there a way to fix it?
I don't know why you compare cell with indexPath.
[indexPath isEqual:self.selectedCell]
If you just want expand selected cell.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[tableView indexPathForSelectedRow] isEqual:indexPath])
{
return 100;
}
return 44;
}
UITableViewDelegate has deselect method
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
You need reload cell in this delegate
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
You need to store that particular index path in array to indicate that it is expanded Lets say you had selected 5 row that store that row number in an array, and reload that row after selecting it
Here is small code snippet that can help you to achieve this
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if([_arrExpandedRows containsObject:indexPath.row]){
[_arrExpandedRows removeObject:indexPath.row];
}else{
// [_arrExpandedRows removeAllObjects]; // IF you only want to make it work for single row
[_arrExpandedRows addObject:indexPath.row];
}
[tableView reloadData];
}
And in your heightForRowAtIndexPath
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([_arrExpandedRows containsObject:indexPath.row]){
{
return 100;
}
return 44;
}
So what will it do if your array contains object of expanded row it will make reduce its row height and back to 44 and if not it will make it back to 100.
And above code will also work for multiple rows to expand and collapse at same time.
I think what you want is unselect cell when tap on a selected cell.
Store selectedIndexPath and compare in delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([selectedIndexPath isEqual:indexPath])
{
[tableView deselectRowAtIndexPath:indexPath animated:1];
}
else
{
selectedIndexPath = indexPath;
}
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
You can do something like this:
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UITableView* tableView;
#property (nonatomic, strong) NSMutableArray* selectedIndexPaths;
#end
<...>
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:CELL_ID];
cell.textLabel.text = [NSString stringWithFormat:#"%i", (int)indexPath.row];
return cell;
}
#pragma mark UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = 44.0;
if ([_selectedIndexPaths containsObject:indexPath])
{
height = 100;
}
return height;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{//store or remove selected indexPaths
if ([_selectedIndexPaths containsObject:indexPath])
{
[_selectedIndexPaths removeObject:indexPath];
}
else
{
[_selectedIndexPaths addObject:indexPath];
}
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

iPhone - UILabel staying outside of the UITableViewCell

I am making a UITableViewController that resizes UITableViewCell when I select the cell.
My problem is that the content that should be hidden when the cell is not expanded (UILabel), is always visible.
What am I doing wrong? Here is my code:
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"TableViewCell";
TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil] objectAtIndex:0];
}
cell.label.text = #"cenas";
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (self.selectedCellIndexPath != nil && indexPath.row == self.selectedCellIndexPath.row) {
return 200;
}else{
return 44;
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (self.selectedCellIndexPath != nil && self.selectedCellIndexPath.row == indexPath.row) {
self.selectedCellIndexPath = nil;
}else{
self.selectedCellIndexPath = indexPath;
}
[tableView beginUpdates];
[tableView endUpdates];
}
And here are some pictures of what is happening:
In cellForRowAtIndexPath put the following code
if (self.selectedCellIndexPath != nil && indexPath.row == self.selectedCellIndexPath.row)
{
[YourLabel setHidden:NO];
}
else
{
[YourLabel setHidden:YES];
}
I found! I finally found!
I inserted inside of cellForRowAtIndexPath: the following:
[cell setClipsToBounds:YES];
This makes the content be only inside the cell
You need to manually hide/show the labels (Preferably with animation). Just because they are not inside the cells height, it doesn't mean they are hidden.
-(void)setSelectedCellIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell *oldCell = [self.tableView cellForRowAtIndexPath:_selectedIndexPath];
//oldCell can be nil due to possibility that it's not on screen.
[self hideOutletsForCell:oldCell];
_selectedIndexPath = indexPath;
UITableViewCell *newCell = [self.tableView cellForRowAtIndexPath:_selectedIndexPath];
[self showOutletsForCell:newCell];
}
Also, you need to reset the outlets in cellForRowAtIndexPath, and only show outlets for the indexPath that is your _selectedIndexPath

UITableViewCells disappears randomly on drag after resize another row

I have a UITableView. I use this code to resize the selected row:
-(void) viewWillAppear:(BOOL)animated {
....
[self.tableView registerNib:[UINib nibWithNibName:#"ICSceneDetailViewTableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:IC_CELL_SCENE_EDITOR_CELL];
...
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == nil)
return 0;
if (self.scenes != nil) {
return self.scenes.count;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ICSceneDetailViewTableViewCell *cell = (ICSceneDetailViewTableViewCell*)[tableView dequeueReusableCellWithIdentifier:IC_CELL_SCENE_EDITOR_CELL forIndexPath:indexPath];
if (cell == nil) {
cell = [[ICSceneDetailViewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:IC_CELL_SCENE_EDITOR_CELL];
}
ICScene *scene = [self.scenes objectAtIndex:[indexPath row]];
[cell.titleTextField setText:scene.title];
return cell;
}
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedRow = indexPath.row;
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath row] == self.selectedRow) {
return 250;
}
if (IS_IPAD) {
return 80;
}
else {
return 40;
}
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
BUT, after selecting any row (name it A, and A become resized):
if I drag another row (name it B) then randomly other rows disappears (except A).
if I scroll tableview and back to drag on same row (B) then, again randomly, other(s) cell(s) disappear(s), but not always the same(s).
if I comment heightForRowAtIndexPath then drag behavior is normal, but row can't be resized :(
I already searched many similar answers (adjusting selectedBackgroundView on cell, backgroundView cell, drawRect on cell, etc) but no one solution/workaround works for this simple (i think) code.
Thanks in advance :)
Yeh, answering my own question.
I found an alternative to resize selected UITableViewCell without calling to reloadRowsAtIndexPaths.
Replacing reloadRowsAtIndexPaths with:
[self.tableView beginUpdates];
[self.tableView endUpdates];
refreshes visible rows without calling cellForRowAtIndexPath. Imho the problem where dequeuing cells on every row being reloaded.
The resulting code is:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedRow = indexPath.row;
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
So, automagically there isn't any disappearing row :)

can we change the height of current row in UITableView?

A very simple question...
can we change the height of only current row(the row which is clicked) in UItableView?
Note: I dont want any affect on size of remaining rows.
Yes you can. You need a variable that keeps the last selected row. For ex.:
#property (nonatomic, assign) NSInteger selectedRow;
...
Then implement the method
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == self.selectedRow) {
return 100.;
}
return 44.;
}
and then, update the method:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if(self.selectedRow == indexPath.row)
self.selectedRow = -1;
else
self.selectedRow = indexPath.row;
//The magic that will call height for row and animate the change in the height
[tableView beginUpdates];
[tableView endUpdates];
}
NOTE: Initialise your self.selectedRow with -1 value in the beginning as the default is 0.
You can use heightForRowAtIndexPath for setting height for a row
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
You can place a check for NSIndexPath and return height for that particular indexpath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == rowtochangeheight) {
return 60;
}
else
{
return 44;
}
}
Yes you can do, But you need to save indexpath of selected row and you must intialize selectedRow variable by negative value.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedRow = indexpath.row;
[tblView reloadData];
}
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == selectedRow)
return 150.0f;
return 30;
}

Resources