As described in the title, I want to hide a cell and not remove it from the table. Is there a way to go about doing this?
You can use next: set variable that handle cell state (hidden or not):
- (float)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == _cellRow)
return _cellHidden ? 0.0f : _cellHeight;
}
And when you want to hide or show cell ask to reload it. This will trigger previous method.
_cellHidden = YES;
[_tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:0 inSection:0]]
withRowAnimation:UITableViewRowAnimationAutomatic]
Related
I want to do min/max (expand/collapse) button functionality.Please see bellow image for more information.Is anybody know how to develop this functionality.I have some examples but those are not like exactly what i want.Please help me to solve this problem.
I've got a similar kinda requirement few days back. I have done this using custom tableview cell.
Firstly, you have to pass the indexpath of each row to the cell. For this i have taken a property in custom tableview cell.
i.e, #property(nonatomic,assign) NSIndexPath *indexPathOfCell;
Now, you have to pass the indexpath of row in datasource method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
And you have to write a delegate method in custom tableviewcell so that when the user clicks on the min/max button you can reload that cell through this delegate call.
-(void)reloadCellWithIndexPath:(NSIndexPath*)indexPath;
You have to set the view controller as delegate for the custom tableview cell in which you are populating the table. In that class you have to maintain an NSMutableArray.
NSMutableArray *selectedIndexPaths;
When ever the reloadCellWithIndexPath gets called you can simply do same.
-(void)reloadCellWithIndexPath:(NSIndexPath*)indexPath{
if(![selectedIndexPaths containsObject:indexPath]){
[selectedIndexPaths addObject:indexPath];
}else
[selectedIndexPaths removeObject:indexPath];
[tableView reloadData];
}
In heightForRowAtIndexPath method you can change the height for a particular row.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
BOOL cellModeChanged = NO;
for (NSIndexPath *indexpath in selectedIndexPaths) {
if(indexpath.section == indexPath.section && indexpath.row == indexPath.row)
cellModeChanged = YES;
}
if(cellModeChanged)
return 400.0;
else
return 100.0;
}
When I compile my app in the new iOS7, I found a problem when entering in the edit mode of an UITableView.
When I press in the red minus button to delete a row of the table, this row indent to the left to let appear the 'Delete' button. However, when this button appears, the text of the cell overlaps the editingAccesory (this happens only when the text is longer than the length of the cell).
How can I remove the overlapping?
Edit: Images in the comments
Edit 2: Tis is the code of the creation of the table
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_tweetList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"SessionDetailCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Tweet *tweet = [_tweetList objectAtIndex:indexPath.row];
cell.textLabel.text = tweet.text;
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView beginUpdates];
Tweet *deletedTweet = [_tweetList objectAtIndex:indexPath.row];
[_selectedSession removeTweetsObject:deletedTweet];
[deletedTweet deleteEntity];
_tweetList = [Tweet findAllSortedBy:#"index" ascending:YES withPredicate:[NSPredicate predicateWithFormat:#"session == %#",_selectedSession]];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
[[NSManagedObjectContext defaultContext]saveToPersistentStoreWithCompletion:nil];
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
selectedPath = indexPath;
[self performSegueWithIdentifier:#"EditTweet" sender:self];
}
Solution:
Finally, I put the accessoryButton in the default state, and I use the edit state only to delete the rows. It's the only solution I've found :(
Perhaps, the method "willTransitionToState" can help people to solve similar problems.
You can hide or remove editingAccesory in editing mode , so there is no overlapping there,
set this,
Screenshot:
I came across this question, because in iOS 8.3 I faced the same problem, that it seems not possible to correctly display the editing accessory AND the delete confirmation without the cell content and the accessory item to overlap. Solving this issue without breaking the transition-animations was quite a challenge. ;)
So here is my solution (assuming that you are using autolayout constraints in IB):
Create a UITableViewCell subclass and link it to your table view cell in IB.
Add an outlet from the autolayout constraint specifying the horizontal spacing bewteen the right-most view and the cell's content view (trailing to margin).
Override willTransitionToState and layoutSubviews as shown below.
Table cell subclass:
#IBOutlet weak var horizontalSpaceConstraint: NSLayoutConstraint!
override func willTransitionToState(state: UITableViewCellStateMask) {
if (state & UITableViewCellStateMask.ShowingDeleteConfirmationMask == UITableViewCellStateMask.ShowingDeleteConfirmationMask) {
self.horizontalSpaceConstraint.constant = 49.0; // ugly, delete-confirmation width
}
super.willTransitionToState(state)
}
override func layoutSubviews() {
if (!self.showingDeleteConfirmation) {
self.horizontalSpaceConstraint.constant = 0.0;
}
super.layoutSubviews()
}
The reason why I cannot use didTransitionToState() (and use layoutSubviewsinstead) to reset the layout constraint is, that this function is simply not invoked (as of iOS 8.3) after transitioning from the delete-confirmation-state. It seems Apple did only handle the case, that the user actually deletes the row, but not the case that the delete-confirmation is closed without deleting the row. :(
I've a problem with my UITableView inside PopoverController.
When I touch cell, the didSelectRowAtIndexPath function is called, and the cell accessoryType is changed. Example simplified :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.listItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.tableView reloadData];
[self.popoverController dismissPopoverAnimated:YES];
}
It's working, the cell are checked, but it's not visible on my tableview : I can't see the blue checkmark. However, in touch state on the cell, the checkmark is visible in white (and the cell background is gray). But not visible in default state.
Do you have any idea why my checkmark are not visible in default state ?
Thanks,
Edit: Add screenshot, for a cell with accessoryType = UITableViewCellAccessoryCheckmark
This happened to me when I changed the global tint color to white. Once I realized, I went into the UITableView and change the tint color locally for just this table. Fixed.
I've tried the answer Jacky Boy - didn't help. But something was there in the deselection...
So I've tried to deselect the cell in the didSelectRowAtIndexPath: before adding the checkmark accessory:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell* selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (row != _selectedRow) {
if (selectedCell.accessoryType == UITableViewCellAccessoryNone) {
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
_selectedRow = row;
} else if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark) {
selectedCell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView reloadData];
}
}
And for me it worked at last - the nice dark checkmark now is clearly visible on the cell!
Of course there is a part in cellForRowAtIndexPath: similar to described in arexx's answer.
I had a similar problem where, after reloading the row with a checkmark set as the accessory, the checkmark wouldn't be visible (but would be visible in white when the row was selected). In testing around the problem I discovered that the checkmark is always present in the cell, it's just white-on-white.
My understanding of the problem is that when I ask for the cell to be reloaded (so that I can show it with a checkmark), the existing cell is put on the reuse queue, but is at that time in a selected state (because the user just selected it). It's still in a selected state when the cell comes back off the reuse queue and you re-configure it in tableView:cellForRowAtIndexPath, and because it's selected, the accessory is set in white instead of in a visible colour.
To fix this, I added a line in tableView:cellForRowAtIndexPath to force the cell not to be selected. The accessory is now always visible when the new cell is displayed.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get a reusable cell - this only works with Storyboard prototype cells
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
// THE MAGIC BIT
// Force the cell to not be in a selected state.
cell.selected = NO;
// END MAGIC BIT
if (indexPathIsPathOfSelectedRow) {
// This is the selected cell, so show the checkmark accessory.
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
// In case we're reusing a cell that previously showed a checkmark, clear it.
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Mine was the most stupidest reason. I had created a tableview in storyboard, with a View Controller of size 5.5 inch and forgot to apply the layout constraints.
Then I launched in a 4 inch phone, Everything looked fine except the accessory view was not visible because of tableviews width was greater than that of the phone screen. It took me 3 hours to find out my mistake.
You are reloading the UITableView so in theory the cells are recreated and this time without the checkmark. Do the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.listItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.popoverController dismissPopoverAnimated:YES];
}
Running under iOS 6.1, the behavior I see is a cell with a white check mark on an almost white background. This appears to be happening because the code that draws the check mark accessory believes the cell is in a highlighted state, so rather than drawing the check mark in the normal blue color, it is drawn in white.
Setting the selected state of the cell did not work for me but setting the highlighted state immediately before setting the accessory type did. With the following in place, I always get a dark blue check mark.
cell.highlighted = NO;
if (checked)
self.accessoryType = UITableViewCellAccessoryCheckmark;
else
self.accessoryType = UITableViewCellAccessoryNone;
If you want to reload Data then you should store selected Id in some variable for single selection like rowIndex and then in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//check index
if (rowIndex==indexPath.row)
{cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
Thanks.
-(UIImageView *)checkmarkImg{
UIImage *image = [[UIImage imageNamed:#"ic_check_black_24dp.png"] changeColor:CLR_BUY];
UIImageView *checkmark = [[UIImageView alloc] initWithImage:image];
return checkmark;
}
cell.accessoryView = [self checkmarkImg];
I have what must be a simple problem with EasyTableView (https://github.com/alekseyn/EasyTableView)
I have a number of horizontally scrolling tables that function properly.
I am able to select a cell and perform a segue, however, once the new view controller is dismissed, I am no longer able to select that cell and perform the same action until I have selected another cell in the same table.
My question is: How can I deselect previously selected the cell programmatically to renable this particular action.
Thanks in advance!
The selectedIndexPath is intentionally persistent in case a user scrolls the selected tableview cell offscreen and then back again. If you don't want this persistence please add the line shown below, after the delegate method (in EasyTableView.m):
- (void)setSelectedIndexPath:(NSIndexPath *)indexPath {
if (![_selectedIndexPath isEqual:indexPath]) {
NSIndexPath *oldIndexPath = [_selectedIndexPath copy];
_selectedIndexPath = indexPath;
UITableViewCell *deselectedCell = (UITableViewCell *)[self.tableView cellForRowAtIndexPath:oldIndexPath];
UITableViewCell *selectedCell = (UITableViewCell *)[self.tableView cellForRowAtIndexPath:_selectedIndexPath];
if ([delegate respondsToSelector:#selector(easyTableView:selectedView:atIndexPath:deselectedView:)]) {
UIView *selectedView = [selectedCell viewWithTag:CELL_CONTENT_TAG];
UIView *deselectedView = [deselectedCell viewWithTag:CELL_CONTENT_TAG];
[delegate easyTableView:self
selectedView:selectedView
atIndexPath:_selectedIndexPath
deselectedView:deselectedView];
// Add this line here!
_selectedIndexPath = nil;
}
}
}
I have a couple of rows in a table view which I like to edit.
I thought that setEditing method would give me a Edit and Delete button, but it only shows a Delete button. Because I don't have a detail view controller that's going to be pushed in didSelectRowAtIndexPath I thought I could show a couple of editing elements in the selected cell.
I need to add three buttons to specify priority on assignments: Low, High and Medium priority. This means that I have to change the height of the selected cell to make room for these buttons, I think that's rather easy to do.
What I'm wondering is if this is the correct path to choose?
I have done quite a lot research today without finding examples of how other have solved editing in a UITableViewCell. If you edit a contact in the Contacts app in the iPhone the UITableViewCells changes to enable quick and easy editing, that's what I'm looking for.
So what do you have for tips for me regarding this question?
Edit #1
My code in didSelectRowAtIndexPath is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *selectedCell = (Cell *)[tableView cellForRowAtIndexPath: indexPath];
UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btn.frame = CGRectMake(0, 0, 50, 100);
btn.titleLabel.text = #"Set this item to High Priority";
btn.backgroundColor = [UIColor greenColor];
[selectedCell.contentView addSubview: btn];
self.editing = YES;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject: indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
Code for heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *cell = nil;
if (self.editing)
cell = (Cell *)[tableView cellForRowAtIndexPath: indexPath];
else
cell = nil;
BOOL expandCell = NO;
NSInteger expandationHeight = 0;
if (cell != nil)
{
for (UIButton *btn in cell.contentView.subviews)
{
NSLog(#"A button was found.");
expandationHeight = 70;
expandCell = YES;
}
}
return expandationHeight + heightOfOtherElements;
}
When I click at a cell nothing happends but everything becomes disabled, I can't click any elements on the hole view. This has something to do with [tableView cellForRowAtIndexPath: indexPath], because if I uncomment that line the UI does not become disabled.
What am I doing wrong?
That's not too complicated though it requires some stuff.
You want to change the content of one cell or of all cells?
To specify a specific height for one cell, use the - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath delegate method.
It is called for each cell each time the table view is displayed. If you want to change a single row, call reloadRowsAtIndexPaths:withRowAnimation: method from UITableView. If you want to update all cells, simply use - (void)reloadData method.
You can also access a specific cell using - (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath method from UITableView. Then you can reconfigure it to add various elements on it, as you want.
Thus, when a cell is selected, check whether you have to edit it or not, then :
update your cell get from cellForRowAtIndexPath
be sure your method tableView:heightForRowAtIndexPath: will return the good height
tell the table view to update the view using reloadRowsAtIndexPaths:withRowAnimation: