UITableViewCell、スワイプ時に削除ボタンを表示


568

スワイプ時に削除ボタンを表示するにはどうすればよいUITableViewCellですか?イベントは発生せず、削除ボタンは表示されません。


1
詳細で更新された回答を探している人は、stackoverflow.com
a / 37719543/6872794に

Sのアクションを削除するスワイプを作成する3つまでの異なる方法を示す同様の質問については、私のSwift 4回答を参照しくださいUITableViewCell
Imanou Petit 2017

私は8年前にこの質問をしました...古くなっているこの質問を削除してください。スウィフトは存在しませんでした!
TheLearner

サイドスワイプボタンの高さを修正できますか?例:セルが150で、ボタンを50.0fだけに表示したいのですが可能ですか?
Suhas Arvind Patil

これは行でうまく機能しますが、セクションをどのように統合するかについての手がかりはありますか?
フロストモーン

回答:


1035

起動時(-viewDidLoad or in storyboard)

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を返す場合は、それを実装する必要はありません。
Thanos Diacakis 2012年

24
また、知っておくことが重要です。これらはUITableViewDataSourceメソッドであり、UITableViewDelegateメソッドではありません
デイブアルバート

8

12
明確にするために-tableView:commitEditingStyle:forRowAtIndexPath:をオーバーライドする必要があります。そうしないと、スワイプジェスチャが認識されず、削除しようとしても何も起こりません。
Chris

これは私には(最初は)うまくいきませんでした。self.tableView.allowsMultipleSelectionDuringEditing = NO;左スワイプが機能するように設定する必要もありました。テーブルが編集状態ではないため、これはバグのように思えます。このオプションは「DuringEditing」にのみ適用されます。ただし、現在は機能しており、テーブルが編集状態になるたびにYESに設定します。
osxdirk 2014年

118

この回答はSwift 3に更新されました

新しいタスクを学習するときに何も想定されないように、非常に単純な自己完結型の例があるといいといつも思っています。この答えは、UITableView行を削除するためのものです。プロジェクトは次のように実行されます。

ここに画像の説明を入力してください

このプロジェクトは、SwiftのUITableViewサンプルに基づいています

コードを追加する

新しいプロジェクトを作成し、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ストーリーボードのビューコントローラーにを追加します。自動レイアウトを使用して、テーブルビューの4つの側面をビューコントローラーの端に固定します。ストーリーボードのテーブルビューから@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向けに更新

アクションは、iOS 11のUITableViewDelegate APIに追加されたメソッドを使用して、セルの先頭または末尾に配置できます。

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])
 }

参考文献


例とコードをありがとう。これで、削除機能を実装する準備ができました。viewDidLoad()に追加した「self.tableView.registerClass(...」行の目的は何ですか?また、インターフェースビルダーのそれと同等のものは何ですか?カスタムセルの例にはありませんでした。 cellReuseIdentifierを2回指定しているようです。ありがとう!
rockhammer

.registerClass行を含めると、コンパイルが失敗する
rockhammer

@rockhammer、そのとおりです。コードとインターフェイスビルダーの両方でセル再利用識別子を設定する必要はありません(明らかにできません)。好みに応じて、1つの方法を選択してください。このプロジェクトはに基づいているが、その基本的なUITableView1、これは完全にスタンドアロンのプロジェクトであり、あなたがここで説明されていない何もする必要はありません。私がコードでそれを設定し始めた理由はそれが私の答えであまり説明を必要としないからです。コードに戻るには、基本的な例に戻って編集する必要があります。
Suragch

どのように右スワイプを実装しますか?セル内で左スワイプで何かを「拒否」し、右スワイプで何かを「受け入れる」と言いますか?
Munib 2016年

1
@ return0は、私の知る限り、右スワイプ機能が組み込まれていないため、ゼロから作成する必要があります。試したい場合は、この記事を参考にしてください。ただし、ユーザーが期待する標準的なアクションではないため、この方法はお勧めしません。むしろ、上記の私の回答のカスタムボタンアクションセクションのように、左スワイプで2つのボタンの選択肢を表示します。
Suragch 2016年

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 '19

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];

つまり、テーブルが編集モードのときにのみ複数選択が有効になります。


これは役に立ちました。ストーリーボードでallowsMultipleSelectionを設定しました。これはそれを修正しました。
Mark Suman、2014年

1
これは、私たちを混乱させた問題を解決しました。「スワイプして削除」と「編集モードでのバッチ削除」は基本的に相互に排他的であり、編集モードに入るとき、または編集モードに入るときにそれを制御する必要があることを理解しました。これを研究してくれてありがとう!
fbitterlich 2014

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 16

11

@クルブズの答えは素晴らしいですが、私はこのメモを残して、この答えが人々の時間を節約できることを願っています。

コントローラーにこれらのラインが時々あり、スワイプ機能が動作しなくなりました。

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

UITableViewCellEditingStyleInsertまたはUITableViewCellEditingStyleNone編集スタイルとして使用する場合、スワイプ機能は機能しません。UITableViewCellEditingStyleDeleteデフォルトのスタイルであるのみを使用できます。


1
私の場合、スワイプして削除できるようにしたいが、その後、セルを移動できるようにしたかった。移動可能なセルには、セルの左側にあるこの「削除」ボタンがあり、これは私のデザインに適合していません。これを削除するには、編集スタイルを.noneにする必要があります。「if tableView.isEditing {return .none} else {return .delete}」によってこれを解決しました

私の斧の男を救った。ありがとう:)
Sourav Chandra

9

スウィフト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 2017年

はい "// indexPathでアイテムを削除します" indexPathに基づいて削除行のロジックを配置します
Pratik 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

あなたがしなければならないすべてはこれらの2つの機能を有効にすることです:

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にデータを追加したりすると、オブジェクトは存在しなくなります。

それ以外の場合は、Kurbzからの正解です。

DataSource配列からオブジェクトを削除する場合、デリゲート関数では十分ではないことを思い出させたいだけです。

お役に立てば幸いです。



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

スウィフト4,5

スワイプでセルを削除するには、UITableViewの2つの組み込みメソッドがあります。このメソッドをTableView dataSource拡張に書き込みます。

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)
            }
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.