UITableViewCell, показать кнопку удаления при прокрутке


568

Как я могу получить кнопку удаления, чтобы показать при наведении на UITableViewCell? Событие никогда не вызывается и кнопка удаления никогда не появляется.


1
Если вам нужен подробный и обновленный ответ, перейдите к stackoverflow.com/a/37719543/6872794
— Munib

Смотрите мой ответ Swift 4 для аналогичного вопроса, который показывает до 3 различных способов создания пролистывания, чтобы удалить действия для UITableViewCells.
— Imanou Petit

Я задал этот вопрос 8 лет назад ... пожалуйста, удалите этот вопрос, он сильно устарел. Свифта даже не было!
— TheLearner

мы можем сделать фиксирование высоты для боковых кнопок смахивания? Например: моя ячейка 150, и я хочу, чтобы кнопка показывала только 50.0f, возможно ли это?
— Сухас Арвинд Патил

это отлично работает на строках, но есть какие-нибудь подсказки о том, как интегрировать его в разделы?
— Ледяная Скорбь

Ответы:


1035

Во время запуска в (-viewDidLoad or in storyboard)do:

self.tableView.allowsMultipleSelectionDuringEditing = NO;

Переопределить для поддержки условного редактирования табличного представления. Это нужно реализовать только в том случае, если вы собираетесь возвращаться NOза некоторыми предметами. По умолчанию все элементы доступны для редактирования.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
    }    
}

94
Это работает, но ... - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath ... необходимо реализовать только в том случае, если вы собираетесь возвращать NO для некоторых элементов. По умолчанию все элементы доступны для редактирования, поэтому вам не нужно реализовывать их, если вы всегда возвращаете YES.
— Танос Дьякакис

24
Также важно знать: это методы UITableViewDataSource и NOT UITableViewDelegate.
— Дейв Альберт


12
Просто для ясности - вы ДОЛЖНЫ переопределить tableView: commitEditingStyle: forRowAtIndexPath: или жест смахивания не будет распознан, и при попытке удаления ничего не произойдет.
— Крис

Это не сработало для меня (сначала). Мне также нужно было установить self.tableView.allowsMultipleSelectionDuringEditing = NO;левое движение для работы. Для меня это звучит как ошибка, потому что таблица НЕ находится в состоянии редактирования. Эта опция должна применяться только во время редактирования. Тем не менее, он работает сейчас, и я установил его в YES всякий раз, когда таблица переходит в состояние редактирования.
— osxdirk

118

Этот ответ был обновлен до Swift 3

Я всегда думаю, что хорошо иметь очень простой, автономный пример, чтобы ничего не предполагалось, когда я изучал новое задание. Это ответ для удаления UITableViewстрок. Проект работает так:

введите описание изображения здесь

Этот проект основан на примере UITableView для Swift .

Добавить код

Создайте новый проект и замените код ViewController.swift следующим.

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // These strings will be the data for the table view cells
    var animals: [String] = ["Horse", "Cow", "Camel", "Pig", "Sheep", "Goat"]

    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // It is possible to do the following three things in the Interface Builder
        // rather than in code if you prefer.
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
        tableView.delegate = self
        tableView.dataSource = self
    }

    // number of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.animals.count
    }

    // create a cell for each table view row
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!

        cell.textLabel?.text = self.animals[indexPath.row]

        return cell
    }

    // method to run when table view cell is tapped
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }

    // this method handles row deletion
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

        if editingStyle == .delete {

            // remove the item from the data model
            animals.remove(at: indexPath.row)

            // delete the table view row
            tableView.deleteRows(at: [indexPath], with: .fade)

        } else if editingStyle == .insert {
            // Not used in our example, but if you were adding a new row, this is where you would do it.
        }
    }

}

Метод с одним ключом в приведенном выше коде, который позволяет удалять строки, является последним. Здесь это снова для акцента:

// this method handles row deletion
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == .delete {

        // remove the item from the data model
        animals.remove(at: indexPath.row)

        // delete the table view row
        tableView.deleteRows(at: [indexPath], with: .fade)

    } else if editingStyle == .insert {
        // Not used in our example, but if you were adding a new row, this is where you would do it.
    }
}

Раскадровка

Добавьте UITableViewк View Controller в раскадровке. Используйте автоматическое расположение, чтобы прикрепить четыре стороны табличного представления к краям контроллера вида. Управляйте перетаскиванием из табличного представления в раскадровке на @IBOutlet var tableView: UITableView!строку в коде.

Законченный

Это все. Теперь вы сможете запустить свое приложение и удалить строки, проведя пальцем влево и нажав «Удалить».


вариации

Изменить текст кнопки «Удалить»

введите описание изображения здесь

Добавьте следующий метод:

func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
    return "Erase"
}

Пользовательские действия кнопок

введите описание изображения здесь

Добавьте следующий метод.

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    // action one
    let editAction = UITableViewRowAction(style: .default, title: "Edit", handler: { (action, indexPath) in
        print("Edit tapped")
    })
    editAction.backgroundColor = UIColor.blue

    // action two
    let deleteAction = UITableViewRowAction(style: .default, title: "Delete", handler: { (action, indexPath) in
        print("Delete tapped")
    })
    deleteAction.backgroundColor = UIColor.red

    return [editAction, deleteAction]
}

Обратите внимание, что это доступно только в iOS 8. Смотрите этот ответ для более подробной информации.

Обновлено для iOS 11

Действия могут быть размещены в начале или в конце ячейки с помощью методов, добавленных в API UITableViewDelegate в iOS 11.

func tableView(_ tableView: UITableView,
                leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
 {
     let editAction = UIContextualAction(style: .normal, title:  "Edit", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
             success(true)
         })
editAction.backgroundColor = .blue

         return UISwipeActionsConfiguration(actions: [editAction])
 }

 func tableView(_ tableView: UITableView,
                trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
 {
     let deleteAction = UIContextualAction(style: .normal, title:  "Delete", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
         success(true)
     })
     deleteAction.backgroundColor = .red

     return UISwipeActionsConfiguration(actions: [deleteAction])
 }

дальнейшее чтение


спасибо за примеры и код. Теперь я готов реализовать функцию удаления. Подскажите, пожалуйста, какова цель строки "self.tableView.registerClass (...", которую вы добавили в viewDidLoad ()? И что эквивалентно этому в построителе интерфейса? Этого не было в примере с пользовательской ячейкой. Похоже, что мы указываем cellReuseIdentifier дважды сейчас. Спасибо!
— Rockhammer

Если включить строку .registerClass, компиляция не удалась
— rockhammer

@rockhammer, Вы правы, вам не нужно (по-видимому, нельзя) установить идентификатор повторного использования ячейки как в коде, так и в Интерфейсном Разработчике. Просто выберите один из способов в соответствии с вашими предпочтениями. Несмотря на то, что этот проект основан на том основные UITableViewодин , это совершенно самостоятельный проект , и вам не нужно ничего делать, не описанные здесь. Причина, по которой я начал устанавливать его в коде, заключается в том, что он требует меньше объяснений в моих ответах. Я должен вернуться и отредактировать основной пример, чтобы использовать код тоже.
— Сурагч

Как можно осуществить правильный удар? Скажи, что левый удар «отклоняет» что-то, а правый удар «принимает» что-то в ячейке?
— Munib

1
@ return0, насколько я знаю, функция смахивания вправо не встроена, поэтому вам придется создавать ее с нуля. В этой статье вы найдете идеи, с которых можно начать, если вы хотите попробовать. Тем не менее, я бы не советовал делать это, поскольку это не стандартное действие, которое ожидает пользователь. Скорее, я бы показал два варианта выбора кнопок влево, как в разделе действий с пользовательскими кнопками в моем ответе выше.
— Сурагч

70

Этот код показывает, как реализовать удаление.

#pragma mark - UITableViewDataSource

// Swipe to delete.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [_chats removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }
}

При желании в переопределении инициализации добавьте строку ниже, чтобы показать элемент кнопки «Редактировать»:

self.navigationItem.leftBarButtonItem = self.editButtonItem;

Вы должны реализовать этот метод. Содержимое внутри должно соответствовать тому, что имеет смысл для вашего варианта использования. В приведенном выше коде _chats - это данные для представления таблицы. Как только пользователь нажимает «удалить», отдельный объект чата должен быть удален из _chat, чтобы источник данных отражал количество новых строк (в противном случае выбрасывается исключение).
— ewcy

25

У меня была проблема, которую мне только что удалось решить, поэтому я делюсь ею, так как она может кому-то помочь.

У меня есть UITableView и добавил показанные методы, чтобы разрешить удаление салфетки:

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
    }    
}

Я работаю над обновлением, которое позволяет мне перевести таблицу в режим редактирования и активирует множественный выбор. Для этого я добавил код из образца Apple TableMultiSelect . Как только я заработал эту работу, я обнаружил, что моя функция удаления перестала работать.

Оказывается, добавление следующей строки к viewDidLoad было проблемой:

self.tableView.allowsMultipleSelectionDuringEditing = YES;

С этой строкой мультиселект будет работать, но удаление не будет. Без линии все было наоборот.

Исправление:

Добавьте следующий метод в ваш viewController:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    self.tableView.allowsMultipleSelectionDuringEditing = editing; 
    [super setEditing:editing animated:animated];
}

Затем в вашем методе, который переводит таблицу в режим редактирования (например, нажатием кнопки), вы должны использовать:

[self setEditing:YES animated:YES];

вместо:

[self.tableView setEditing:YES animated:YES];

Это означает, что множественный выбор включается только тогда, когда таблица находится в режиме редактирования.


Это было полезно. Я установил allowMultipleSelection в раскадровке. Это исправило это.
— Марк Суман

1
Это решило проблему, которая сводила нас с ума. Теперь я понимаю, что «смахивание для удаления» и «пакетное удаление в режиме редактирования» в основном являются взаимоисключающими, и вы должны контролировать это при входе в режим редактирования / ухода. Большое спасибо за исследование этого!
— fbitterlich

18

Ниже UITableViewDataSource поможет вам для удаления

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [arrYears removeObjectAtIndex:indexPath.row];
        [tableView reloadData];
    }
}

arrYears является NSMutableArray, а затем перезагрузите tableView

стриж

 func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
            return true
        }

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == UITableViewCellEditingStyleDelete {
        arrYears.removeObjectAtIndex(indexPath.row)
        tableView.reloadData()
    }
}

Но это UITableViewDataSource
— HotJard

17

В iOS 8 и Swift 2.0 попробуйте это,

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
   // let the controller to know that able to edit tableView's row 
   return true
}

override func tableView(tableView: UITableView, commitEdittingStyle editingStyle UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)  {
   // if you want to apply with iOS 8 or earlier version you must add this function too. (just left in blank code)
}

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]?  {
   // add the action button you want to show when swiping on tableView's cell , in this case add the delete button.
   let deleteAction = UITableViewRowAction(style: .Default, title: "Delete", handler: { (action , indexPath) -> Void in

   // Your delete code here.....
   .........
   .........
   })

   // You can set its properties like normal button
   deleteAction.backgroundColor = UIColor.redColor()

   return [deleteAction]
}

Это хороший ответ, с его помощью вы также можете настроить несколько действий.
— Munib

11

Ответ @ Kurbz потрясающий, но я хочу оставить эту заметку и надеюсь, что этот ответ может спасти людей некоторое время.

У меня иногда были эти строки в моем контроллере, и они заставляли функцию свипирования не работать.

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleNone; 
}

Если вы используете UITableViewCellEditingStyleInsertили UITableViewCellEditingStyleNoneкак стиль редактирования, то функция смахивания не работает. Вы можете использовать только UITableViewCellEditingStyleDeleteстиль по умолчанию.


1
В моем случае я хотел иметь возможность провести удаление, но также и иметь возможность перемещать свои ячейки. Подвижная ячейка также получает эту кнопку «удалить» в левой части ячейки, которая не вписывалась в мой дизайн, и для удаления этого стиля редактирования должен быть .none. Я решил это следующим образом: "если tableView.isEditing {return .none} else {return .delete}"

Спас мой Axz чувак. Спасибо :)
— Сурав Чандра

9

Swift 4

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let delete = UITableViewRowAction(style: .destructive, title: "delete") { (action, indexPath) in
        // delete item at indexPath
    tableView.deleteRows(at: [indexPath], with: .fade)

    }
    return [delete]
}

1
Хорошо, появляется вкладка удаления, но не удаляется при нажатии. Вам нужно удалить объект в источнике данных и перезагрузить таблицу да?
— user3069232

да "// удалить элемент в indexPath" разместить логику вашей строки удаления на основе indexPath
— Lad

8

Кроме того, это может быть достигнуто в SWIFT с использованием метода следующим

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if (editingStyle == UITableViewCellEditingStyle.Delete){
        testArray.removeAtIndex(indexPath.row)
        goalsTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    }
}

8

Свифт 3

Все, что вам нужно сделать, это включить эти две функции:

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {

    return true

}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == UITableViewCellEditingStyle.delete {
        tableView.reloadData()
    }

}

7

Я знаю, это старый вопрос, но ответ @Kurbz просто нужен для Xcode 6.3.2 и SDK 8.3

Мне нужно добавить [tableView beginUpdates]и [tableView endUpdates](спасибо @ bay.phillips здесь )

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    // Open "Transaction"
    [tableView beginUpdates];

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // your code goes here
        //add code here for when you hit delete
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
     }

    // Close "Transaction"
    [tableView endUpdates];
}

6

Когда вы удаляете ячейку вашего табличного представления, вы также должны удалить объект массива с индексом x.

Я думаю, что вы можете удалить его, используя жест пальцем. Представление таблицы вызовет делегата:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
        [dataSourceArray removeObjectAtIndex:indexPath.row];
    }    
}

После удаления объекта. Вы должны перезагрузить использование таблицы. Добавьте следующую строку в ваш код:

[tableView reloadData];

после этого вы успешно удалили строку. И когда вы перезагрузите представление или добавите данные в DataSource, объект больше не будет там.

Для всего остального правильный ответ от Курбца.

Я только хотел напомнить вам, что функции делегата будет недостаточно, если вы хотите удалить объект из массива DataSource.

Я надеюсь, что помог вам.


4
Вместо того, чтобы [tableView reloadData]звонить [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic].
— ma11hew28

6
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        //add code here for when you hit delete
        [dataSourceArray removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }    
}    

dataSourceArray - массив, из которого поступает содержимое ячейки
— Rahul K Rajan

2

Swift 2.2:

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

override func tableView(tableView: UITableView,
    editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let delete = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "DELETE"){(UITableViewRowAction,NSIndexPath) -> Void in

    print("Your action when user pressed delete")
}
let edit = UITableViewRowAction(style: UITableViewRowActionStyle.Normal, title: "EDIT"){(UITableViewRowAction,NSIndexPath) -> Void in

    print("Your action when user pressed edit")
}
    return [delete, block]
}

2

Для Swift, просто напишите этот код

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            print("Delete Hit")
        }
}

Для Objective C, просто напишите этот код

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
       if (editingStyle == UITableViewCellEditingStyleDelete) {           
            NSLog(@"index: %@",indexPath.row);
           }
}

2

для кода swift4 сначала включите редактирование:

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true
}

затем вы добавляете действие удаления к делегату редактирования:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let action = UITableViewRowAction(style: .destructive, title: "Delete") { (_, index) in
        // delete model object at the index
        self.models[index.row]
        // then delete the cell
        tableView.beginUpdates()
        tableView.deleteRows(at: [index], with: .automatic)
        tableView.endUpdates()

    }
    return [action]
}

0

Swift 4,5

Чтобы удалить ячейку при пролистывании, есть два встроенных метода UITableView. Запишите этот метод в расширение DataSource TableView.

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let delete = deleteProperty(at: indexPath)
        return UISwipeActionsConfiguration(actions: [delete])
    }

//Declare this method in Viewcontroller Main and modify according to your need

func deleteProperty(at indexpath: IndexPath) -> UIContextualAction {
        let action = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completon) in
            self.yourArray.remove(at: indexpath) //Removing from array at selected index

            completon(true)
        action.backgroundColor = .red //cell background color
    }
        return action
    }

0

Если вы используете расширяемые источники данных, вам придется переместить обратные вызовы делегатов в UITableViewDiffableDataSourceподкласс. Например:

class DataSource: UITableViewDiffableDataSource<SectionType, ItemType> {

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            if let identifierToDelete = itemIdentifier(for: indexPath) {
                var snapshot = self.snapshot()
                snapshot.deleteItems([identifierToDelete])
                apply(snapshot)
            }
        }
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.