So basically what I am doing now is expanding my cells by selecting on them and using heightForRowAtIndexPath to change their height and if I select on it again or select a different cell those cells will expand or go back to their normal size.
However, upon the cell expanding I have some extra data to show in the expanded section, change the background color of the cell and set some other properties that I have defined in my tableviewcell subclass. So as an example when the cell is in its normal height the background will be light green. When its expanded it needs to be white. I set my tableviewcell subclass property (a BOOL) so that when its time to loop through the cells again (cellforRowatindexpath) i can update these properties as needed. Unfortunately, I haven't been able to find a way to get the current cell thats been selected in cellForRowAtIndexPath.
Here is the relevant code below. Keep in mind that I want to keep track of the current cell selected and the previous cell (if different from the current one) so that i can update both cells properties. Only one cell can be expanded at a time. When the current cell is selected and expanded the previous one(if applicable) will contract back to normal height. My configureCell method is just there to assign the properties based its BOOL property.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier forIndexPath:indexPath];
[cell configureCell:self.item[indexPath.row] isCollapsed:cell.isCollapsed];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *currentCell;
MyCustomCell *previousCell;
self.currentSelectedIndex = indexPath;
//assign previous and current if previous is nil
if(!self.previousSelectedIndex){
self.previousSelectedIndex = self.currentSelectedIndex;
currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
currentCell.isCollapsed = NO;
}
//we have tapped the same cell as before
else if(self.previousSelectedIndex == self.currentSelectedIndex){
previousCell = [tableView cellForRowAtIndexPath:self.previousSelectedIndex];
previousCell.isCollapsed = YES;
self.previousSelectedIndex = self.currentSelectedIndex = nil;
}
//if they aren't equal, then collapse the previous selected cell
//and expand the current selected cell
else{
previousCell = [tableView cellForRowAtIndexPath:self.previousSelectedIndex];
previousCell.isCollapsed = YES;
currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
currentCell.isCollapsed = NO;
self.previousSelectedIndex = self.currentSelectedIndex;
}
[tableView beginUpdates];
if(self.currentSelectedIndex){
[tableView reloadRowsAtIndexPaths:#[self.currentSelectedIndex, self.previousSelectedIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[tableView endUpdates];
}
So, obviously my current and previous cell will be trashed once we leave this method since they are local but I am struggling with how to:
a. reload the cells which would cause cellForRowAtIndexPath to execute again(this works when trying to use reloadRows - but maybe I'm doing that wrong)
b.once cellForRowAtIndex starts going through the cells how to capture the currentCell and the previousCell so that i can update its content as I described above. [dequeueReusableCellWithIdentifier:myIdentifier] just gets a new cell which I do not want obviously.
The cells expand and contract fine so thats not an issue.
Related
Here is my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier=#"menucell";
MenuCell *cell = (MenuCell*) [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell==nil)
cell= [[MenuCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] ;
MenuModel *resturntent = (self.menuList)[indexPath.row];
cell.foodNameLbl.text = resturntent.MenuName;
cell.priceLbl.text = [NSString stringWithFormat:#"%# %#",#"$" , resturntent.MenuRate];
cell.foodImage.image = [UIImage imageNamed:#"full_breakfast.jpg"];
return cell;
}
While scrolling uitextfields values gets duplicates .
I need help to fix this issues
When you use dequeueReusableCellWithIdentifier, your cells will be reused. This means when the user scrolls the tableview, a cell which moves out of the screen will be reused to display the contents of a cell which is about to move onto the screen.
Even though this helps in saving memory, the problem it causes is the that the cell needs to be prepared for display before it is loaded with the content of the new cell.
In your case, it seems you need to maintain the values the user has entered in a textfield of a cell.
So to fix your problem, if there are not that many cells in the tableview, simply stop reusing the cell. Else whenever the user enters a value in the textfield of a cell, save it in an array (array of 'MenuModel' in your case). And fetch the value from from the model and set it to your textfield in the cellForRowAtIndexPath method like your have set values for other labels.
I want to change a specific UIImageView inside a UITableViewCell with this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView beginUpdates];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UYLTextCell *textCell = (UYLTextCell *)cell;
textCell.selected = YES;
//get and show the image at selected cell
textCell.testImage.image = [UIImage imageNamed:#"image280280.jpg"];
//[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
But what happened is some cell had their image View even though it has not been clicked.
Table views re-use cells. When a cell is scrolled offscreen it is added to a queue, and will be re-used for the next cell to be scrolled onscreen. That means your cell configuration code in tableView:cellForRowAtIndexPath: should be enough to properly configure any cell, including cells that were previously selected at a different indexPath. In tableView:didSelectRowAtIndexPath: store the selected index path in a property and use that property to configure your cell in tableView:cellForRowAtIndexPath:. The image will need to be set in tableView:cellForRowAtIndexPath: whether the cell is selected or not (unless you implement prepareForReuse in your custom cell).
So I've created a TableView as below, but I have quite an annoying problem.
When I come to this VC, I click Choose User, and I selected user Atoshum.
When I scroll down, this top cell goes off screen as I scroll through the bottom cells.
When I scroll back up, the cell has reverted to a default (or occasionally, takes the value of another cell).
I make the cells as such.
static NSString *CellIdentifier = #"Cell";
DMSDrugInstanceCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!Cell) {
Cell = [[DMSDrugInstanceCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Cell.chooseUserButton.tag = indexPath.row;
[Cell.chooseUserButton addTarget:self
action:#selector(performSegue:)
forControlEvents:UIControlEventTouchUpInside];
return Cell;
In the cell creation you dont ever set any values. All you do is set the tag and then add an event target. If you want it to keep the choose, you need to store/save that choice when it is made and then in the cell create, set it based on that saved value.
you are reusing table cell. So every time your cell reload then you need to set value in cell.
in cellForRowAtIndexPath method , you need to set value in cell according to index path.
This is because the UITableView do not create the new cells for total number of elements. Rather it re-uses the cells which are off the visibility. Hence you feel that your data is reset or getting reflected on some other cell.
The best approach is to store all your data in some Array (let it be tagDataArray) and then set your cells as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
DMSDrugInstanceCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[DMSDrugInstanceCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Cell.chooseUserButton.tag = [tagDataArray objectAtIndex:indexPath.row];
...
...
return Cell;
}
I'm using a custom UITableViewCell subclass, called MessageCell.
I initialise the cell like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MessageCell *cell = [tableView dequeueReusableCellWithIdentifier:#"messageCell"];
// more code
return cell;
}
In each custom cell I have a checkbox used to mark this cell. When a cell is marked it is being added to an array, and vice versa.
While this works in terms of data, the UI is not reflecting it as it should. What happens is that in addition to the marked cell, other cells are being marked.
I assume this behaviour stems from cell reusability, i.e when I mark a cell as selected it has a common pointer with all future cells in this screen position.
For this reason, I want to use "normal" non-reusable cells.
So I tried:
MessageCell *cell = [[MessageCell alloc] init];
OR:
MessageCell *cell = [[MessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
But both of them resulted in displaying empty cells.
You still want to reuse cells! Just check your data and set the checkbox to checked or unchecked in your cellForRowAtIndexPath:
MessageCell *cell = [tableView dequeueReusableCellWithIdentifier: #"messageCell"];
if (condition cell should be checked) //set the cells checkbox to checked
else //set the cells checkbox to unchecked
Or some approach like that.
PS on re-reading your question:
do you really need a reference to a cell in your array? Can't you for example store the indexPath and use cellForRowAtIndexPath: if you need to make a cell out of it?
How could I easily dim the complementary set of rows, when one gets selected.
Right now I have the code to select a cell so I can call a method on it, but I would like to set opacity of all the other rows.
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SummaryCell * selectedCell = [tableView cellForRowAtIndexPath:indexPath];
[selectedCell manageContent];
}
Edit: I dont want to iterate through all the other cells (because there will be a lot of them) - wouldn't it be easier to add an UIView above all other cell (this would also prevent user interaction) and place the selected cell above that view (something like increasing z-index in HTML).
It depends what you mean by "dim" the other rows. The process to iterate over all visible rows and to set a property on all the rows other than the one selected is as follows:-
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
for (UITableViewCell *otherCell in self.tableView.visibleCells) {
NSIndexPath *otherIndexPath = [self.tableView indexPathForCell:otherCell];
if (![indexPath isEqual:otherIndexPath]) { // exclude the selected cell
// Do whatever you want with otherCell here
}
}
}
Where my comment is, you can set whatever properties you like on otherCell. For example, otherCell.alpha which is the alpha (transparency) of that cell.
You can iterate all the visible cells, configure them to be dimmed, then on the datasource cellForIndex method check if there's a selected cell, if there is, check if it is at the asked index, if so configure the cell as selected, if not as dimmed.