UITableViewRowAction: Delete - uitableview

I want to let the user to be able to delete a table cell at the moment I have the delete swipe action but I don't know how to actually delete the selected cell! As you can tell I am programming in Swift and Xcode 6.3.1
var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action, indexPath) -> Void in
tableView.editing = false
println("deleteAction")
}
Here is screenshot on dropbox as well: Screenshot Of Delete Swipe Action

If you want to remove a cell completely from tableView then you have to remove it from your table Array too. Consider below code:
var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action, indexPath) -> Void in
tableView.editing = true
// Remove it from your TableArray and If it is stored into any local storage then you have to remove it from there too because if you doesn't remove it from your local storage then when you reload your tableview it will appears back
self.tableData.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
return [deleteAction]
}

This might help you.
func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
// handle delete (by removing the data from your array and updating the tableview)
if let tv=tableView
{
items.removeAtIndex(indexPath!.row)
tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}

You must implement editActionsForRowAtIndexPath and commitEditingStyle
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
__weak SampleViewController *weakSelf = self;
UITableViewRowAction *actionRed =
[UITableViewRowAction
rowActionWithStyle:UITableViewRowActionStyleNormal
title:#"Delete"
handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
NSLog(#"Delete!");
[weakSelf.itemsList removeObjectAtIndex:indexPath.row];
[weakSelf.tableView setEditing:NO animated:YES];
[weakSelf.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}];
actionRed.backgroundColor = [UIColor colorWithRed:0.844 green:0.242 blue:0.292 alpha:1.000];
return #[actionRed];
}
/*
* Must implement this method to make 'UITableViewRowAction' work.
*
*/
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
}
Here is an example ActionRowTest

Related

Swift 3 - Reload UICollectionView inside the UITableViewCell

I have a UICollectionView inside a UITableViewCell. You may refer the image at here
I would like to reload the collectionView if any update happen.
I have done some research and found this :
how to reload a collectionview that is inside a tableviewcell
Reloading collection view inside a table view cell happens after all cells in table view have been loaded
UICollectionView not updating inside UITableViewCell
I called the #IBOutlet weak var collectionView: UICollectionView! from UITableViewCell to UITableViewController at cellForRowAt.
Here is the code:
var refreshNow: Bool = false
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.allCardCell, for: indexPath) as! AllCardTableViewCell
if refreshNow {
cell.collectionView.reloadData()
refreshNow = false
}
cell.collectionView.collectionViewLayout.invalidateLayout()
return cell
}
If the user click Ok on UIAlertAction :
let alert = UIAlertController(title: "Success", message: "Card successfully added", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .default) { (action) in
self.refreshNow = true
self.tableView.reloadData()
}
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
The reason why I put the refreshNow is to prevent the apps from lagging and slow. But still did not update if any changes happen.
The problem is the collectionView did not refresh. But when I debug, it was went through the cell.collectionView.reloadData().
The update/changes only happen when I restart the apps. I want it to be so called real-times update.
Any help is really appreciated and many thanks.
Image credit: How to use StoryBoard quick build a collectionView inside UITableViewCell
At end of your update add:
DispatchQueue.main.async() { () -> Void in
self.tableView.reloadData()
}
In your case, you should assign tag to your collection view in order to get access outside the cellForRowAt function.
This is how your function should look like:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.allCardCell, for: indexPath) as! AllCardTableViewCell
cell.collectionView.tag = 1234
return cell
}
and the action will reload it will access the collectionView by using the tag
let action = UIAlertAction(title: "Ok", style: .default) { (action) in
let collectionView = self.tableView.viewWithTag(1234) as! UICollectionView
collectionView.reloadData()
}
Also take note that cellForRowAt will keep reload the content based what you added inside it every time the cell appear. So, keep updating your data outside the cellForRowAt function.
Because you reused UITableViewCell so you must alway reload your UICollectionView. If you use refreshNow to reload UICollectionView, at the cell have refreshNow = false, UICollectionView will display like cell that it 's reused => wrong
Udate rep:
See , in picture uitableviewcell 1 will reuse at index 6. If you not reload content of cell (reload collectionview) it will display like uitableviewcell 1 at index 0
#import "AddPhotoViewController.h"
#import "PhotoTableViewCell.h"
#import "ShareTableViewCell.h"
#interface AddPhotoViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tblView;
#property (strong,nonatomic)NSMutableArray *arrImages,*arrIndexPath,*selectImages;
#end
#pragma mark - TableViewDelegate&DataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *returnCell;
static NSString *cellIdentifier = #"CellOne";
static NSString *cellIdentifierTwo = #"CellTwo";
static NSString *cellIdentifierThree = #"CellThree";
if (indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
returnCell = cell;
} else if (indexPath.row == 1){
ShareTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierTwo forIndexPath:indexPath];
cell.viewMood.layer.cornerRadius = 5;
cell.viewPeople.layer.cornerRadius = 5;
[cell.viewMood layer].borderWidth = 1;
[cell.viewMood layer].borderColor = [UIColor colorWithRed:241.0/255.0 green:143.0/255.0 blue:48.0/255.0 alpha:1].CGColor;
[cell.viewPeople layer].borderWidth = 1;
[cell.viewPeople layer].borderColor = [UIColor colorWithRed:241.0/255.0 green:143.0/255.0 blue:48.0/255.0 alpha:1].CGColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
returnCell = cell;
}else if (indexPath.row == 2){
PhotoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierThree forIndexPath:indexPath];
cell.collView.dataSource = self;
cell.collView.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
returnCell = cell;
}
return returnCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticDimension;
}
#pragma mark- UIImagePickerControllerDelegate
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
[_arrImages addObject:chosenImage];
PhotoTableViewCell *cell = [self.tblView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
[cell.collView reloadData];
[picker dismissViewControllerAnimated:YES completion:^{
}];
}
#pragma mark - CollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [_arrImages count];
}
- ( UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"CellCollection";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImageView *imgView = [(UIImageView*)[cell contentView] viewWithTag:100];
UIImageView *imgViewTick = [(UIImageView*)[cell contentView] viewWithTag:200];
UIView *view = [(UIView*)[cell contentView] viewWithTag:300];
if (indexPath.row == 0){
imgViewTick.hidden = YES;
view.hidden = YES;
}
if ([_arrIndexPath containsObject:indexPath]) {
[_selectImages removeAllObjects];
view.hidden = NO;
view.alpha = 0.4;
imgViewTick.hidden = NO;
imgView.image = [_arrImages objectAtIndex:indexPath.row];
[_selectImages addObject:[_arrImages objectAtIndex:indexPath.row]];
NSLog(#"Pick images:%#",_selectImages);
}else{
view.hidden = YES;
imgViewTick.hidden = YES;
imgView.image = [_arrImages objectAtIndex:indexPath.row];
}
return cell;
}

How to select multiple rows in UITableView in edit mode?

I want to ask, how can I forward to edit mode, where I can to select multiple rows, as in Messages app, when you click on top right button "Select", when you can choose multiple messages by tapping on circles.
Like this:
I searched a lot, really, but couldn't find anything. Can anyone help me? Some advices
Set
tableView.allowsMultipleSelectionDuringEditing = true
Screenshot
Demo code
class TableviewController:UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(true, animated: false)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
If you're using Storyboards do this:
NSMutableArray *selected;
decleare it in you viewcontroller.h file..
selected =[[NSMutableArray alloc]init];
for (int i=0; i<[YOUR_ARRAY count]; i++) // Number of Rows count
{
[selected addObject:#"NO"];
}
add same number of "NO" in selected array using above code for that you had to replace YOUR_ARRAY with your data array that you show in table.
if(![[selected objectAtIndex:indexPath.row] isEqualToString:#"NO"])
{
cell.accessoryType=UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType=UITableViewCellAccessoryNone;
}
put above code in your -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selected replaceObjectAtIndex:path.row withObject:#"YES"];
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
[selected replaceObjectAtIndex:path.row withObject:#"NO"];
}
}
also put this to work correctly..

UITableView commitEditingStyle only on particular cases

Is it possible to make editable the UITableView by adding the commitEditingStyle method only under certain circumstances ?
I have a controller.m/.h file that is doing stuff for 3 differents storyboards viewcontrollers. I want only 2 of the 3 to be able to commitEditingStyle. I can distinguish them using the self.restorationIdentifier.
you can check tableview tag..
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableview.tag==1 || tableview.tag==2)
return UITableViewCellEditingStyleDelete;
return UITableViewCellEditingStyleNone;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
//here your code
}
}
public override UITableViewCellEditingStyle EditingStyleForRow(UITableView tableView, NSIndexPath indexPath)
{
//here we show and hide the delete for particular row
if (indexPath.Row ==1)
{
return UITableViewCellEditingStyle.Delete;
}
else {
return UITableViewCellEditingStyle.None;
}
}
public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
{
if (editingStyle == UITableViewCellEditingStyle.Delete)
{
//here we handle delete button action of the tableview
}
}
Well, seems that I had simply to subclass and add the commitEditingStyle on the subclass. Then change the class in the storyboard to the subclass and that's all.

How can I get the class (custom) of cell selected in UITableView?

Usually I get my selected cell this way:
- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell*) [table cellForRowAtIndexPath:indexPath];
}
But in the code I'm working with, I may have many kind of cells in my table view. How can I get the class of my selected cell (if it's for example CustomCell or CustomCell2) ?
You can check the type of cell returned
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[CustomCell class]]) {
//do specific code
}else if([cell isKindOfClass:[CustomCell2 class]]){
//Another custom cell
}else{
//General cell
}
SWIFT 4
Just in case, if someone needed it. Get the instance of selected cell and then check it for required tableViewCell type.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = myCustomCell.cellForRow(at: indexPath)
else
{
return
}
/** MyCustomCell is your tableViewCell class for which you want to check. **/
if cell.isKind(of: MyCustomCell.self)
{
/** Do your stuff here **/
}
}

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