Removing UITableViewCell Selection - ios

Currently I'm overriding the standard UITableViewSelectionStyle by using UITableViewSelectionStyleNone and then changing the color the cell based on delegate methods:
- (void)tableView:(UITableView *)tableView
didHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor yellowColor]];
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor whiteColor]];
}
- (void)tableView:(UITableView *)tableView
didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"indexpath: %i",indexPath.row);
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor whiteColor]];
}
- (void)tableView:(UITableView *)tableView
didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor whiteColor]];
}
This almost works except that whenever I highlight a cell and then drag my finger off of it without actually selecting it, the color doesn't change to white...if I set it to [UIColor RedColor] it works perfeclty. Why is this...
Edit:
Somehow when I print out the indexPath.row after didUnhlightRowAtIndexPath I get "indexpath: 2147483647" from my NSLog

You could try:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
if you just want the highlight to go away after selecting a cell. Unless I misunderstand your question.

You can also try this
tableView.allowsSelection = NO;
another way of doing this
cell.selectionStyle = UITableViewCellSelectionStyleNone;
one more
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

You can also do it from the storyboard. Select the tableViewCell and under Attributes Inspector you can choose Selection > None

Here is a Swift 2 version
if let indexPaths = self.tableView.indexPathsForSelectedRows {
for indexPath in indexPaths {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}

Unselect selected row(s). You do not even need to know which one it is.
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)

By maintaing a local instance of my indexPath, I was able to find the last selected cell and change its color to whitecolor. Seems really annoying that I have to maintain state myself, but it is what it is...

How about doing this with an extension?
import UIKit
extension UITableView {
func removeRowSelections() {
self.indexPathsForSelectedRows?.forEach {
self.deselectRow(at: $0, animated: true)
}
}
}
Usage:
tableView.removeRowSelections()

Simplest solution that worked for me (Swift 4.2)
(if you still want table view's row to be selectable)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let index = self.tableView.indexPathForSelectedRow{
self.tableView.deselectRow(at: index, animated: true)
}
}

Related

How to get multiple selected row value from uitableview and save multiple selected value in array? [duplicate]

This question already has answers here:
Select multiple rows in UITableview [duplicate]
(5 answers)
Closed 6 years ago.
I have list of states in UITableView.Now i want to select multiple row of UITableView and wanna get this selected row values in one array.how can i get this?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSMutableArray *arrData =[statearray objectAtIndex:indexPath.row];
NSLog(#"arrdata>>%#",statearray);
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [statearray objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
You can call tableview.indexPathForSelectedRows. This will output an array with the indexpaths for all selected rows in your tableview!
This is how your code would look like in swift 3:
var values : [String] = []
let selected_indexPaths = tableView.indexPathsForSelectedRows
for indexPath in selected_indexPaths! {
let cell = tableView.cellForRow(at: indexPath)
values.append((cell?.textLabel?.text)!)
}
After running this code the values of all selected cells should be in the values array.
you can keep track of selected cells with below way
var selectedCells: [UITableViewCell] = []
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCells.append(tableView.cellForRow(at: indexPath)!)
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let deselectedRow = tableView.cellForRow(at: indexPath)
if(selectedCells.contains(deselectedRow!)){
let indx = selectedCells.index(of: deselectedRow!)
selectedCells.remove(at: indx!)
}
}
Idea is to maintain array of selected cells when cell selection happens and remove cell once deselection is done
Best way is to get selected indexpaths using method
tableView.indexPathsForSelectedRows
you can get the data out in an array
var oldArray: [NSIndexPath] = [NSIndexPath.init(row: 0, section: 0), NSIndexPath.init(row: 1, section: 0), NSIndexPath.init(row: 2, section: 0), NSIndexPath.init(row: 3, section: 0)]
var newArray: [Int] = oldArray.flatMap { ($0.row) }
Like if we have array in form of oldArray, We can get only rows using flatMap.
There is default method of tableview,
self.tableView.indexPathsForSelectedRows
Which gives you an array of selected indexpaths. But you need to also set property of tableview
self.tableView.allowsMultipleSelection = true
If want back selcted rows to track,
NSArray *selectedRowsArray = [yourTableViewName indexPathsForSelectedRows];
Answer updated
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//the below code will allow multiple selection
if ([yourMutableArray containsObject:indexPath])
{
[yourMutableArray removeObject:indexPath];
}
else
{
[yourMutableArray addObject:indexPath];
}
[yourTableView reloadData];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if ([yourMutableArray containsObject:indexPath])
{
//Do here what you wants
if (contentArray.count > 0) {
NSDictionary *dictObje = [contentArray objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[dictObje objectForKey:#"name"]];
}
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
//Do here what you wants
if (contentArray.count > 0) {
NSDictionary *dictObje = [contentArray objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[dictObje objectForKey:#"name"]];
}
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}

reloadRowsAtIndexPaths cannot reload index path as expected

I add a image as avatar at indexPath [0,0], and use detailLabel display nickname at indexPath [0,1].
When use reloadRowsAtIndexPaths indexPath the indexPath [0,1] get a image...
I find when invoke reloadRowsAtIndexPaths the dequeue cell return nil.
Maybe the [0,0] cell be reuse at [0,1], I don't know why so that.
The code is:
- (void)viewDidLoad {
[super viewDidLoad];
_titles = #[#"Avator", #"Nickname"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_avator = [UIImage imageNamed:#"cat"];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_nickName = #"Smallfly";
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
});
});
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _titles.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *const cellIdenfier = #"cellIdentifier";
// Why reloadRowsAtIndexPaths [0,0] returned cell is nil?
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdenfier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdenfier];
}
if (indexPath.row == 0) {
[self configureCell:cell indexPath:indexPath];
} else {
NSString *nickName = _nickName ?: #"nickname";
cell.detailTextLabel.text = nickName;
}
cell.textLabel.text = _titles[indexPath.row];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
for (UIView *sv in cell.contentView.subviews) {
if ([sv isKindOfClass:[UIImageView class]]) {
[sv removeFromSuperview];
}
}
UIImage *avator = _avator ?: [UIImage imageNamed:#"user_profile_avatar"];
UIImageView *avatorImageView = [[UIImageView alloc] initWithImage:avator];
...
[cell.contentView addSubview:avatorImageView];
}
reloadRowsAtIndexPaths is a void method.
dequeueReusableCell always returns a cell (remove UITableViewCell alloc)
Objective-C
- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
withRowAnimation:(UITableViewRowAnimation)animation
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:#"reuseIdentifier"
forIndexPath:indexPath];
// Configure the cell...
return cell;
}
Swift 3
open func reloadRows(at indexPaths: [IndexPath],
with animation: UITableViewRowAnimation)
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier",
for: indexPath)
// Configure the cell...
return cell
}
You may want to look at a more recent tutorial or sample code.

Hide a custom UITableViewCell from another UITableViewCell class

I have two cells, let's say cell A and cell B in my app. Both of them have their own class, class CellA : UITableViewCell and class CellB : UITableViewCell.
I wish to hide cell B when user tap on a button in cell A.
How can I achieve this? Thanks.
if you want to hide cell B when tapping on a button in cell A (not the cell A itself), I think the good way is just to post a notification when clicking the button, let the UIViewController know it,then remove the datasouce of cellB and reloadData.
If you are using Static tableview content, just create two outlet of cell, lets say Cell1 and Cell2 with respective class of A and B with action methods actn_methodCell1 and actn_methodCell2
-(void)actn_methodCell1{ //action method for button in cell1
Cell2.hidden = YES;
[self.tableview reloadData];
}
-(void)actn_methodCell2{ //action method for button in cell2
Cell1.hidden = YES;
[self.tableview reloadData];
}
OR If you are using prototype tableview then, code this in didSelectCell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath{
UITableViewCell *cell = [self.tableview cellForRowAtIndexPath:indexPath.row];
if([cell isKindOfClass:[A class]]){
for (UITableViewCell *cell in self.tableview) {
if([cell isKindOfClass:[B class]]){
cell.hidden = YES;
}
}
}
else if ([cell isKindOfClass:[B class]]){
for (UITableViewCell *cell in self.tableview) {
if([cell isKindOfClass:[A class]]){
cell.hidden = YES;
}
}
}
[self.tableview reloadData];
}

UiTableViewCell is not displaying in Storybord

UiTableViewCell is not displaying in Storybord,
UiTableViewCell is not displaying in Storybord,UITableViewCell is not displaying in Storybord can any one help me Thanks in advance
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 50;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 100;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ContactsCell";
ContactsCell *cell = (ContactsCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[ContactsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.accessoryType=UITableViewCellAccessoryCheckmark;
cell.accessoryType=UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
Have you set Delegate and DataSource of you UITableView?
Using,
[self.IByourTableView setDelegate:self];
[self.IByourTableView setDataSource:self];
Update #1: For answer comment(ie: Open ChatViewController),
for that use delegate method of UITableView
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var storyBoardName = "Main"
var storyBoard:UIStoryboard?
storyBoard = UIStoryboard(name: storyBoardName, bundle: nil)
var gotoViewController: UIViewController? = storyBoard?.instantiateViewControllerWithIdentifier("YourViewControllerIdentifier") as? UIViewController
navigationController?.pushViewController(gotoViewController!, animated: true)
}
Note:Go to Story board and give Identifier to your ChatViewController
you wrote nothing to display in table
in cellforrow at indexpath add below line
cell.textlable.text=#"add something";
or replace your cellforrowatindexpath with below code
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ContactsCell";
ContactsCell *cell = (ContactsCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[ContactsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.accessoryType=UITableViewCellAccessoryCheckmark;
cell.accessoryType=UITableViewCellAccessoryDetailDisclosureButton;
cell.textlable.text=#"add something";
return cell;
}
Do you know that you can't make UITableViewCell appear in storyboard by writing code? All the code you wrote will only display in the device.
You want UITableViewCell to appear in storyboard then you need to open storyboard and start adding and editing your uitableviewcell not by writing code.

How to remove the check mark on another click?

I want to make a table that user can select and deselect with a check mark:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
...;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
- (void)tableView:(UITableView *) tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...;
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
...;
}
I was trying to remove the check mark when clicking on the check-marked cell again, but it takes 2 clicks to do that instead of one.
If I set selection style to default, when I click on a selected row, it removes the blue highlight; clicking again, it removes the check mark.
I also tried some conditional statements in didSelectRowAtIndexPath, but they only respond to second click as well.
What causes the problem and how do I fix it?
You can try this one:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger index = [[tableView indexPathsForVisibleRows] indexOfObject:indexPath];
if (index != NSNotFound) {
UITableViewCell *cell = [[tableView visibleCells] objectAtIndex:index];
if ([cell accessoryType] == UITableViewCellAccessoryNone) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
}
This should toggle the cell's checkmark on every touch.
If you additionally want only one cell to appear selected at a time, also add the following:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger index = [[tableView indexPathsForVisibleRows] indexOfObject:indexPath];
if (index != NSNotFound) {
UITableViewCell *cell = [[tableView visibleCells] objectAtIndex:index];
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
}
If you don't want the blue hilight background, simply set the cell's selection style to UITableViewCellSelectionStyleNone once you create the cell.
Based on Starter's link to Apple docs (my code in Swift 3):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: selectedIndexPath) {
cell.accessoryType = .none
}
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
selectedIndexPath = indexPath
}
The main point is to keep track of currently selected cell and change cell.accessoryType accordingly. Also don't forget to properly set cell.accessoryType in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) based on selectedIndexPath.
Check this Apple official doc
best solution ever
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (index != NSNotFound) {
UITableViewCell *cell = [[tableView visibleCells] objectAtIndex:index];
if (cell.accessoryType == UITableViewCellAccessoryNone)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
[self.tableName reloadData];
}
}
This helps in toggling the checkmarks (remove the check mark when clicking on the check-marked cell again)
You can use this:
You can use this:
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark { tableView.cellForRow(at: indexPath)?.accessoryType = .none } else { tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark } tableView.deselectRow(at: indexPath, animated: true)

Resources