it-swarm.com.de

Zum Löschen streichen und "Mehr" (wie in der Mail-App unter iOS 7)

So erstellen Sie eine Schaltfläche "Mehr", wenn der Benutzer eine Zelle in der Tabellenansicht durchwischt (wie die Mail-App in iOS 7)

Ich habe diese Informationen sowohl hier als auch im Cocoa Touch-Forum gesucht, aber ich scheine keine Antwort zu finden, und ich hoffe, jemand, der klüger ist als ich, kann mir eine Lösung geben.

Wenn der Benutzer über eine Tabellensichtzelle wischt, wird angezeigt, dass mehr als eine Bearbeitungsschaltfläche angezeigt wird (standardmäßig ist die Schaltfläche "Löschen") .. In der Mail-App für iOS 7 können Sie streichen, um zu löschen, aber es gibt ein " MORE "-Taste, die angezeigt wird.

enter image description here

238
Guy Kahlon

Wie umsetzen?

Es sieht so aus, als ob iOS 8 diese API öffnet. Hinweise zu dieser Funktionalität finden Sie in Beta 2. 

Um etwas zum Laufen zu bringen, implementieren Sie die folgenden beiden Methoden in Ihrem UITableView-Delegaten, um den gewünschten Effekt zu erzielen (siehe Gist für ein Beispiel).

- tableView:editActionsForRowAtIndexPath:
- tableView:commitEditingStyle:forRowAtIndexPath:


Bekannte Probleme

Die Dokumentation besagt, dass tableView: commitEditingStyle: forRowAtIndexPath wie folgt lautet:

"Nicht für Bearbeitungsaktionen aufgerufen, die UITableViewRowAction verwenden - stattdessen wird der Handler der Aktion aufgerufen."

Das Wischen funktioniert jedoch nicht ohne. Auch wenn der Methodenstub leer ist, muss er vorerst noch verwendet werden. Dies ist am offensichtlichsten ein Fehler in Beta 2.


Quellen

https://Twitter.com/marksands/status/481642991745265664https://Gist.github.com/marksands/76558707f583dbb8f870

Ursprüngliche Antwort: https://stackoverflow.com/a/24540538/870028


Aktualisieren:

Beispielcode, der funktioniert (In Swift): http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.Zip

Der Beispielcode enthält diese einfach zu befolgende Methode in MasterViewController.Swift. Mit dieser Methode erhalten Sie das im OP-Screenshot dargestellte Verhalten:

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {

    var moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "More", handler:{action, indexpath in
        println("MORE•ACTION");
    });
    moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);

    var deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete", handler:{action, indexpath in
        println("DELETE•ACTION");
    });

    return [deleteRowAction, moreRowAction];
}
123
Johnny

Ich habe eine neue Bibliothek erstellt, um umschaltbare Schaltflächen zu implementieren, die eine Vielzahl von Übergängen und erweiterbare Schaltflächen wie die iOS 8-Mail-App unterstützen.

https://github.com/MortimerGoro/MGSwipeTableCell

Diese Bibliothek ist mit allen Möglichkeiten zur Erstellung einer UITableViewCell kompatibel und wird unter iOS 5, iOS 6, iOS 7 und iOS 8 getestet.

Hier einige Beispiele für Übergänge:

Grenzübergang:

Border transition

Clipübergang

Clip transition

3D-Übergang:

enter image description here

118
MortimerGoro

Johnnys Antwort ist die richtige Antwort. Ich füge dies nur in object-c ein, um Anfängern (und denen von uns, die sich weigern, die Swift-Syntax zu erlernen) klarer zu werden.

Stellen Sie sicher, dass Sie das uitableviewdelegate deklarieren und die folgenden Methoden verwenden:

 -(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
 UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
    {
        NSLog(@"Action to perform with Button 1");
    }];
    button.backgroundColor = [UIColor greenColor]; //arbitrary color
    UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
                                    {
                                        NSLog(@"Action to perform with Button2!");
                                    }];
    button2.backgroundColor = [UIColor blueColor]; //arbitrary color

    return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:

}
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES; //tableview must be editable or nothing will work...
    }
68
timothykc

Dies ist (ziemlich lächerlich) eine private API.

Die folgenden zwei Methoden sind privat und werden an den Delegaten der UITableView gesendet:

-(NSString *)tableView:(UITableView *)tableView titleForSwipeAccessoryButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
-(void)tableView:(UITableView *)tableView swipeAccessoryButtonPushedForRowAtIndexPath:(NSIndexPath *)indexPath;

Sie sind ziemlich selbsterklärend.

25
Jonathan.

Um die Antwort von Johnny zu verbessern, kann dies nun mithilfe der öffentlichen API wie folgt durchgeführt werden:

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {

    let moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "More", handler:{action, indexpath in
        print("MORE•ACTION");
    });
    moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);

    let deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Delete", handler:{action, indexpath in
        print("DELETE•ACTION");
    });

    return [deleteRowAction, moreRowAction];
}
23
Das

Ich hoffe, du kannst es kaum erwarten, bis Apple dir gibt, was immer du brauchst, oder? Also hier ist meine Option.

Erstellen Sie eine benutzerdefinierte Zelle. Habe zwei Ansichten darin 

1. upper
2. lower

Fügen Sie in der unteren Ansicht die gewünschten Schaltflächen hinzu. Handle seine Aktionen nur wie alle anderen IBActions. Sie können die Animationszeit, den Stil und alles andere bestimmen.

fügen Sie nun der oberen Ansicht eine Uiswipegesture hinzu und zeigen Sie Ihre untere Ansicht der Wischgeste. Ich habe dies schon einmal gemacht und es ist die einfachste Option für mich.

Hoffe das hilft.

17
Deepukjayan

Dies ist mit dem Standard-SDK nicht möglich. Es gibt jedoch verschiedene Lösungen von Drittanbietern, die das Verhalten in Mail.app mehr oder weniger nachahmen. Einige von ihnen (z. B. MCSwipeTableViewCell , DAContextMenuTableViewController , RMSwipeTableViewCell ) erkennen Swipes mit Gestenerkennungsfunktionen, einige (z. B. SWTableViewCell ) setzen eine zweite UISScrollView unter den Standardwert UITableViewCellScrollView (private Unteransicht von UITableViewCell) und einige von ihnen ändern das Verhalten von UITableViewCellScrollView

Der letzte Ansatz gefällt mir am besten, da sich das Berührungshandling am natürlichsten anfühlt. Insbesondere ist MSCMoreOptionTableViewCell gut. Ihre Wahl kann abhängig von Ihren spezifischen Anforderungen variieren (ob Sie auch einen Schwenk von links nach rechts benötigen, ob Sie eine iOS 6-Kompatibilität benötigen usw.). Beachten Sie auch, dass die meisten dieser Ansätze mit einer Belastung verbunden sind: Sie können eine zukünftige iOS-Version leicht durchbrechen, wenn Apple Änderungen in der UITableViewCell-Unteransichtshierarchie vornimmt.

7
Ortwin Gentz

Swift 3 Versionscode ohne Verwendung einer Bibliothek:

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        tableView.tableFooterView = UIView(frame: CGRect.zero) //Hiding blank cells.
        tableView.separatorInset = UIEdgeInsets.zero
        tableView.dataSource = self
        tableView.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return 4
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)

        return cell
    }

    //Enable cell editing methods.
    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {

        return true
    }

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

    }

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

        let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
            //self.isEditing = false
            print("more button tapped")
        }
        more.backgroundColor = UIColor.lightGray

        let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
            //self.isEditing = false
            print("favorite button tapped")
        }
        favorite.backgroundColor = UIColor.orange

        let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
            //self.isEditing = false
            print("share button tapped")
        }
        share.backgroundColor = UIColor.blue

        return [share, favorite, more]
    }

}
7
mriaz0011

Sie müssen die Unterklasse UITableViewCell und die Unterklassenmethode willTransitionToState:(UITableViewCellStateMask)state angeben, die aufgerufen wird, wenn der Benutzer die Zelle durchwischt. Die state-Flags zeigen an, ob die Schaltfläche Löschen angezeigt wird, und zeigen/verbergen dort die Schaltfläche Mehr. 

Leider gibt diese Methode weder die Breite der Schaltfläche "Löschen" noch die Animationszeit an. Sie müssen also den Frame und die Animationszeit Ihres More-Buttons in Ihren Code beobachten und fest codieren (ich persönlich glaube, Apple muss etwas dagegen unternehmen).

6
Khanh Nguyen

Für die schnelle Programmierung

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
  if editingStyle == UITableViewCellEditingStyle.Delete {
    deleteModelAt(indexPath.row)
    self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
  }
  else if editingStyle == UITableViewCellEditingStyle.Insert {
    println("insert editing action")
  }
}

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
  var archiveAction = UITableViewRowAction(style: .Default, title: "Archive",handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
        // maybe show an action sheet with more options
        self.tableView.setEditing(false, animated: false)
      }
  )
  archiveAction.backgroundColor = UIColor.lightGrayColor()

  var deleteAction = UITableViewRowAction(style: .Normal, title: "Delete",
      handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
        self.deleteModelAt(indexPath.row)
        self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic);
      }
  );
  deleteAction.backgroundColor = UIColor.redColor()

  return [deleteAction, archiveAction]
}

func deleteModelAt(index: Int) {
  //... delete logic for model
}
4

Dies könnte Ihnen helfen.

-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
 UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
    {
        NSLog(@"Action to perform with Button 1");
    }];
    button.backgroundColor = [UIColor greenColor]; //arbitrary color
    UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
                                    {
                                        NSLog(@"Action to perform with Button2!");
                                    }];
    button2.backgroundColor = [UIColor blueColor]; //arbitrary color

    return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:

}
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES; //tableview must be editable or nothing will work...
    }
3
santoshIOS

Ab iOS 11 ist dies in UITableViewDelegate öffentlich verfügbar. Hier ist ein Beispielcode:

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
    UIContextualAction *delete = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
                                                                         title:@"DELETE"
                                                                       handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
                                                                           NSLog(@"index path of delete: %@", indexPath);
                                                                           completionHandler(YES);
                                                                       }];

    UIContextualAction *rename = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
                                                                         title:@"RENAME"
                                                                       handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
                                                                           NSLog(@"index path of rename: %@", indexPath);
                                                                           completionHandler(YES);
                                                                       }];

    UISwipeActionsConfiguration *swipeActionConfig = [UISwipeActionsConfiguration configurationWithActions:@[rename, delete]];
    swipeActionConfig.performsFirstActionWithFullSwipe = NO;

    return swipeActionConfig;
}

Auch verfügbar:

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath;

Docs: https://developer.Apple.com/documentation/uikit/uitableviewdelegate/2902367-tableview?language=objc

3
Lewis42

Swift 4 & IOs 11+

@available(iOS 11.0, *)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {

    let delete = UIContextualAction(style: .destructive, title: "Delete") { _, _, handler in

        handler(true)
        // handle deletion here
    }

    let more = UIContextualAction(style: .normal, title: "More") { _, _, handler in

        handler(true)
        // handle more here
    }

    return UISwipeActionsConfiguration(actions: [delete, more])
}
3
Andrey

Actual Swift 3 Antwort

Dies ist die EINZIGE Funktion, die Sie benötigen. Sie benötigen keine CanEdit- oder CommitEditingStyle-Funktionen für benutzerdefinierte Aktionen.

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let action1 = UITableViewRowAction(style: .default, title: "Action1", handler: {
        (action, indexPath) in
        print("Action1")
    })
    action1.backgroundColor = UIColor.lightGray
    let action2 = UITableViewRowAction(style: .default, title: "Action2", handler: {
        (action, indexPath) in
        print("Action2")
    })
    return [action1, action2]
}
3
William T.

Ich suchte nach der gleichen Funktionalität für meine App und nachdem ich so viele verschiedene Tutorials durchlaufen hatte ( raywenderlich , die beste DIY-Lösung), stellte ich fest, dass Apple eine eigene UITableViewRowActionclass hat, was sehr praktisch ist. 

Sie müssen die Boilerpoint-Methode von Tableview folgendermaßen ändern:

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]?  {
    // 1   
    var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Share" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
    // 2
    let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .ActionSheet)

    let twitterAction = UIAlertAction(title: "Twitter", style: UIAlertActionStyle.Default, handler: nil)
    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)

    shareMenu.addAction(twitterAction)
    shareMenu.addAction(cancelAction)


    self.presentViewController(shareMenu, animated: true, completion: nil)
    })
    // 3
    var rateAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Rate" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
    // 4
    let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .ActionSheet)

    let appRateAction = UIAlertAction(title: "Rate", style: UIAlertActionStyle.Default, handler: nil)
    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)

    rateMenu.addAction(appRateAction)
    rateMenu.addAction(cancelAction)


    self.presentViewController(rateMenu, animated: true, completion: nil)
    })
    // 5
    return [shareAction,rateAction]
  }

Mehr dazu erfahren Sie unter Diese Seite . Die Eigene Dokumentation von Apple ist wirklich nützlich, um die Hintergrundfarbe zu ändern: 

Die Hintergrundfarbe der Aktionstaste.

Deklaration OBJECTIVE-C @ property (nichtatomisch, Kopie) UIColor * backgroundColor Discussion Mit dieser Eigenschaft können Sie die Hintergrundfarbe für Ihre Schaltfläche festlegen. Wenn Sie keinen Wert für .__ angeben. Bei dieser Eigenschaft weist UIKit eine Standardfarbe zu, die auf dem Wert in .__ basiert. Stilimmobilie.

Verfügbarkeit Verfügbar in iOS 8.0 und höher.

Wenn Sie die Schriftart der Schaltfläche ändern möchten, ist dies etwas schwieriger. Ich habe einen weiteren Beitrag zu SO gesehen. Um den Code sowie den Link bereitzustellen, hier der Code, den sie dort verwendet haben. Sie müssen das Aussehen der Schaltfläche ändern. Sie müssten einen bestimmten Verweis auf tableviewcell angeben, ansonsten würden Sie das Aussehen der Schaltfläche in Ihrer App ändern (ich wollte das nicht, aber Sie könnten, ich weiß es nicht :))

Ziel c: 

+ (void)setupDeleteRowActionStyleForUserCell {

    UIFont *font = [UIFont fontWithName:@"AvenirNext-Regular" size:19];

    NSDictionary *attributes = @{NSFontAttributeName: font,
                      NSForegroundColorAttributeName: [UIColor whiteColor]};

    NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString: @"DELETE"
                                                                          attributes: attributes];

    /*
     * We include UIView in the containment hierarchy because there is another button in UserCell that is a direct descendant of UserCell that we don't want this to affect.
     */
    [[UIButton appearanceWhenContainedIn:[UIView class], [UserCell class], nil] setAttributedTitle: attributedTitle
                                                                                          forState: UIControlStateNormal];
}

Schnell:

    //create your attributes however you want to
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())] as Dictionary!            

   //Add more view controller types in the []
    UIButton.appearanceWhenContainedInInstancesOfClasses([ViewController.self])

Dies ist die einfachste und stromlinienförmigste Version von IMHO. Ich hoffe es hilft.

Update: Hier ist die Swift 3.0 Version:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    var shareAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Share", handler: {(action, cellIndexpath) -> Void in
        let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .actionSheet)

        let twitterAction = UIAlertAction(title: "Twitter", style: .default, handler: nil)
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        shareMenu.addAction(twitterAction)
        shareMenu.addAction(cancelAction)


        self.present(shareMenu,animated: true, completion: nil)
    })

    var rateAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Rate" , handler: {(action, cellIndexpath) -> Void in
        // 4
        let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .actionSheet)

        let appRateAction = UIAlertAction(title: "Rate", style: .default, handler: nil)
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        rateMenu.addAction(appRateAction)
        rateMenu.addAction(cancelAction)


        self.present(rateMenu, animated: true, completion: nil)
    })
    // 5
    return [shareAction,rateAction]
}
3
Septronic

Ich habe tableViewCell verwendet, um mehrere Daten anzuzeigen. Nach dem Wischen () von rechts nach links in einer Zelle werden zwei Schaltflächen angezeigt. Genehmigen ist RejectFunc, die auch ein Argument benötigt. 

 enter image description here

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
        let Approve = UITableViewRowAction(style: .normal, title: "Approve") { action, index in

            self.ApproveFunc(indexPath: indexPath)
        }
        Approve.backgroundColor = .green

        let Reject = UITableViewRowAction(style: .normal, title: "Reject") { action, index in

            self.rejectFunc(indexPath: indexPath)
        }
        Reject.backgroundColor = .red



        return [Reject, Approve]
    }

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

    func ApproveFunc(indexPath: IndexPath) {
        print(indexPath.row)
    }
    func rejectFunc(indexPath: IndexPath) {
        print(indexPath.row)
    }
2
akbar khan

Swift 4

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, sourceView, completionHandler) in
        print("index path of delete: \(indexPath)")
        completionHandler(true)
    }
    let rename = UIContextualAction(style: .normal, title: "Edit") { (action, sourceView, completionHandler) in
        print("index path of edit: \(indexPath)")
        completionHandler(true)
    }
    let swipeActionConfig = UISwipeActionsConfiguration(actions: [rename, delete])
    swipeActionConfig.performsFirstActionWithFullSwipe = false
    return swipeActionConfig
}
1
Vini App

Hier ist eine etwas fragile Methode, die keine privaten APIs oder den Aufbau eines eigenen Systems erfordert. Sie sichern Ihre Wetten ab, dass Apple das nicht kaputt macht und hoffentlich eine API freigeben wird, mit der Sie diese wenigen Codezeilen ersetzen können.

  1. KVO self.contentView.superview.layer.sublayer. Tun Sie dies in init. Dies ist die Ebene von UIScrollView. Sie können keine KVO-"Unteransichten" erstellen.
  2. Wenn sich Unteransichten ändern, finden Sie die Bestätigungsansicht für das Löschen in scrollview.subviews. Dies geschieht im beobachteten Callback.
  3. Verdoppeln Sie die Größe dieser Ansicht und fügen Sie links von ihrer einzigen Unteransicht einen UIButton hinzu. Dies geschieht auch im beobachteten Callback. Die einzige Unteransicht der Löschbestätigungsansicht ist die Schaltfläche "Löschen".
  4. (optional) Das UIButton-Ereignis sollte self.superview nachschlagen, bis es eine UITableView findet und dann eine von Ihnen erstellte Datenquellen- oder Delegatmethode aufruft, z. Sie können den indexPath der Zelle mithilfe von [tableView indexPathForCell: self] finden.

Dies erfordert auch, dass Sie die Standard-Tabellensicht implementieren, die Delegate-Callbacks bearbeitet.

static char kObserveContext = 0;

@implementation KZTableViewCell {
    UIScrollView *_contentScrollView;
    UIView *_confirmationView;
    UIButton *_editButton;
    UIButton *_deleteButton;
}

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        _contentScrollView = (id)self.contentView.superview;

        [_contentScrollView.layer addObserver:self
             forKeyPath:@"sublayers"
                options:0
                context:&kObserveContext];

        _editButton = [UIButton new];
        _editButton.backgroundColor = [UIColor lightGrayColor];
        [_editButton setTitle:@"Edit" forState:UIControlStateNormal];
        [_editButton addTarget:self
                        action:@selector(_editTap)
              forControlEvents:UIControlEventTouchUpInside];

    }
    return self;
}

-(void)dealloc {
    [_contentScrollView.layer removeObserver:self forKeyPath:@"sublayers" context:&kObserveContext];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if(context != &kObserveContext) {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }
    if(object == _contentScrollView.layer) {
        for(UIView * view in _contentScrollView.subviews) {
            if([NSStringFromClass(view.class) hasSuffix:@"ConfirmationView"]) {
                _confirmationView = view;
                _deleteButton = [view.subviews objectAtIndex:0];
                CGRect frame = _confirmationView.frame;
                CGRect frame2 = frame;
                frame.Origin.x -= frame.size.width;
                frame.size.width *= 2;
                _confirmationView.frame = frame;

                frame2.Origin = CGPointZero;
                _editButton.frame = frame2;
                frame2.Origin.x += frame2.size.width;
                _deleteButton.frame = frame2;
                [_confirmationView addSubview:_editButton];
                break;
            }
        }
        return;
    }
}

-(void)_editTap {
    UITableView *tv = (id)self.superview;
    while(tv && ![tv isKindOfClass:[UITableView class]]) {
        tv = (id)tv.superview;
    }
    id<UITableViewDelegate> delegate = tv.delegate;
    if([delegate respondsToSelector:@selector(tableView:editTappedForRowWithIndexPath:)]) {
        NSIndexPath *ip = [tv indexPathForCell:self];
        // define this in your own protocol
        [delegate tableView:tv editTappedForRowWithIndexPath:ip];
    }
}
@end
1
xtravar

Es gibt eine erstaunliche Bibliothek namens SwipeCellKit, die mehr Anerkennung erhalten sollte. Meiner Meinung nach ist es kühler als MGSwipeTableCell. Letztere repliziert das Verhalten der Zellen der Mail-App nicht vollständig, während SwipeCellKit dies tut. Guck mal

1

Hier ist eine einfache Lösung. Es ist in der Lage, benutzerdefinierte UIView in UITableViewCell anzuzeigen und auszublenden. Die Anzeigelogik ist in der von UITableViewCell, BaseTableViewCell, erweiterten Klasse enthalten.

BaseTableViewCell.h 

#import <UIKit/UIKit.h>

@interface BaseTableViewCell : UITableViewCell

@property(nonatomic,strong)UIView* customView;

-(void)showCustomView;

-(void)hideCustomView;

@end

BaseTableViewCell.M

#import "BaseTableViewCell.h"

@interface BaseTableViewCell()
{
    BOOL _isCustomViewVisible;
}

@end

@implementation BaseTableViewCell

- (void)awakeFromNib {
    // Initialization code
}

-(void)prepareForReuse
{
    self.customView = nil;
    _isCustomViewVisible = NO;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

-(void)showCustomView
{
    if(nil != self.customView)
    {
        if(!_isCustomViewVisible)
        {
            _isCustomViewVisible = YES;

            if(!self.customView.superview)
            {
                CGRect frame = self.customView.frame;
                frame.Origin.x = self.contentView.frame.size.width;
                self.customView.frame = frame;
                [self.customView willMoveToSuperview:self.contentView];
                [self.contentView addSubview:self.customView];
                [self.customView didMoveToSuperview];
            }

            __weak BaseTableViewCell* blockSelf = self;
            [UIView animateWithDuration:.5 animations:^(){

                for(UIView* view in blockSelf.contentView.subviews)
                {
                    CGRect frame = view.frame;
                    frame.Origin.x = frame.Origin.x - blockSelf.customView.frame.size.width;
                    view.frame = frame;
                }
            }];
        }
    }
}

-(void)hideCustomView
{
    if(nil != self.customView)
    {
        if(_isCustomViewVisible)
        {
            __weak BaseTableViewCell* blockSelf = self;
            _isCustomViewVisible = NO;
            [UIView animateWithDuration:.5 animations:^(){
                for(UIView* view in blockSelf.contentView.subviews)
                {
                    CGRect frame = view.frame;
                    frame.Origin.x = frame.Origin.x + blockSelf.customView.frame.size.width;
                    view.frame = frame;
                }
            }];
        }
    }
}

@end

Um diese Funktionalität zu erhalten, erweitern Sie einfach die Tabellensichtzelle von BaseTableViewCell.

Als Nächstes erstellen Sie mit Inside UIViewController, das UITableViewDelegate implementiert, zwei Gestenerkennungsfunktionen, um linke und rechte Wischbewegungen zu verarbeiten.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self.tableView registerNib:[UINib nibWithNibName:CUSTOM_CELL_NIB_NAME bundle:nil] forCellReuseIdentifier:CUSTOM_CELL_ID];

    UISwipeGestureRecognizer* leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleLeftSwipe:)];
    leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.tableView addGestureRecognizer:leftSwipeRecognizer];

    UISwipeGestureRecognizer* rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightSwipe:)];
    rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    [self.tableView addGestureRecognizer:rightSwipeRecognizer];
}

Dann fügen Sie zwei Swipe-Handler hinzu

- (void)handleLeftSwipe:(UISwipeGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self.tableView];
    NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];

    UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];

    if([cell respondsToSelector:@selector(showCustomView)])
    {
        [cell performSelector:@selector(showCustomView)];
    }
}

- (void)handleRightSwipe:(UISwipeGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self.tableView];
    NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];

    UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];

    if([cell respondsToSelector:@selector(hideCustomView)])
    {
        [cell performSelector:@selector(hideCustomView)];
    }
}

In cellForRowAtIndexPath von UITableViewDelegate können Sie jetzt benutzerdefinierte UIView erstellen und an die Zelle mit der Warteschlange anhängen.

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCellTableViewCell* cell = (CustomCellTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"CustomCellTableViewCell" forIndexPath:indexPath];

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"CellCustomView"
                                                      owner:nil
                                                    options:nil];

    CellCustomView* customView = (CellCustomView*)[ nibViews objectAtIndex: 0];

    cell.customView = customView;

    return cell;
}

Natürlich ist diese Art des Ladens von benutzerdefiniertem UIView nur für dieses Beispiel. Verwalten Sie es wie Sie möchten.

0
slobodans