Benutzerdefinierte Bearbeitungsansicht in UITableViewCell, während Sie nach links wischen. Objective-C oder Swift


75

So erstellen Sie eine benutzerdefinierte Bearbeitungsansicht in iOS7 UITableView mit Objective C wie Evernote oder Apple Reminders, während Sie nach links wischen. Ich habe versucht, eine benutzerdefinierte BearbeitungAccessoryView festzulegen, aber dies hat nicht funktioniert.

Evernote-Bearbeitungsansicht:

Geben Sie hier die Bildbeschreibung ein Erinnerungen bearbeiten Ansicht:

Geben Sie hier die Bildbeschreibung ein

Mein aktueller Code ist

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSLog(@"delete");
    }
}

Ich habe versucht, das Problem zu lösen mit: (UITableViewController.h)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //make cell

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    [view setBackgroundColor:[UIColor greenColor]];
    //add Buttons to view

    cell.editingAccessoryView = view;

    return cell;
}

Und das gleiche mit: (UITableViewCell)

- (void)willTransitionToState:(UITableViewCellStateMask)state;
- (void)setEditing:(BOOL)editing animated:(BOOL)animated;
- (UIView*)editingAccessoryView;

Können wir die Höhe für die seitlichen Wischknöpfe festlegen? Beispiel: Meine Zelle ist 150 und ich möchte, dass die Schaltfläche nur 50.0f anzeigt. Ist das möglich?
Suhas Arvind Patil

Antworten:


98

Kopieren Sie einfach den Code unten!

-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {

       UITableViewRowAction *editAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"Clona" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
          //insert your editAction here
       }];
       editAction.backgroundColor = [UIColor blueColor];

       UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"Delete"  handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
          //insert your deleteAction here
       }];
       deleteAction.backgroundColor = [UIColor redColor];
return @[deleteAction,editAction];
}

8
Damit diese in meinem Fall angezeigt werden, musste ich auch die dataSource-Methode der Tabellenansicht implementieren - (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editorStyle forRowAtIndexPath: (NSIndexPath *) indexPath; Schon eine leere Implementierung dieser Methode reichte aus, um die Schaltflächen anzuzeigen.
u2Fan

Ich habe dies in Swift konvertiert und es unten als neue Antwort veröffentlicht. stackoverflow.com/a/33748345/470879
MattyG

@sohil welches Bild? Sie haben eine Bildansicht in Ihrer Zelle? Sie erhalten also einen Handler in der von mir geschriebenen Methode, der aufgerufen wird, wenn Sie auf eine der Schaltflächen tippen
Kartik 123

Dies versucht nicht, die Frage zu beantworten. Der Übermittler fragte speziell, wie Symbole für die Wischaktionen anstelle von Text festgelegt werden sollen.
Mattsson

@mattsson, die Frage ist in dieser Hinsicht vage und erwähnt überhaupt keine Symbole. Als Beispiele werden Evernote und Apple Reminders genannt. Die Apple Reminders-App verwendet eine Standardimplementierung wie diese Antwort.
MattyG

43

Swift 3

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

    let editAction = UITableViewRowAction(style: .normal, title: "Edit") { (rowAction, indexPath) in
        //TODO: edit the row at indexPath here
    }
    editAction.backgroundColor = .blue

    let deleteAction = UITableViewRowAction(style: .normal, title: "Delete") { (rowAction, indexPath) in
        //TODO: Delete the row at indexPath here
    }
    deleteAction.backgroundColor = .red

    return [editAction,deleteAction]
}

Swift 2.1

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let editAction = UITableViewRowAction(style: .Normal, title: "Edit") { (rowAction:UITableViewRowAction, indexPath:NSIndexPath) -> Void in
        //TODO: edit the row at indexPath here
    }
    editAction.backgroundColor = UIColor.blueColor()

    let deleteAction = UITableViewRowAction(style: .Normal, title: "Delete") { (rowAction:UITableViewRowAction, indexPath:NSIndexPath) -> Void in
        //TODO: Delete the row at indexPath here
    }
    deleteAction.backgroundColor = UIColor.redColor()

    return [editAction,deleteAction]
}

Hinweis: ab iOS 8


Swift 3 - Swipe scheint nicht zu funktionieren !! Es werden keine Optionen angezeigt !!
Mythicalcoder

@Maven, haben Sie canEditRowAtIndexPath implementiert, um true zurückzugeben?
MattyG

1
Ich habe bemerkt, dass Sie auch mindestens schreiben müssen func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { }oder editActionsForRowAtIndexPathnicht angerufen werden
reojased

1
Wie füge ich Bilder anstelle von Text hinzu?
Januar

Gibt es nicht einen Speicherverlust, wenn Sie einen Abschluss erstellen, auf den verwiesen wird self?
Legonaftik

22

Sie können mit UITableViewRowAction‚s backgroundColorzu Satz benutzerdefinierten Bild oder Sicht. Der Trick ist mit UIColor(patternImage:).

Grundsätzlich wird die Breite des UITableViewRowActionBereichs durch den Titel bestimmt, sodass Sie eine genaue Länge des Titels (oder Leerzeichens) finden und die genaue Größe des Bildes mit festlegen können patternImage.

Um dies zu implementieren, habe ich eine UIViewErweiterungsmethode erstellt.

func image() -> UIImage {
    UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
    guard let context = UIGraphicsGetCurrentContext() else {
        return UIImage()
    }
    layer.render(in: context)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image!
}

und um eine Zeichenfolge mit Leerzeichen und exakter Länge zu erstellen,

fileprivate func whitespaceString(font: UIFont = UIFont.systemFont(ofSize: 15), width: CGFloat) -> String {
    let kPadding: CGFloat = 20
    let mutable = NSMutableString(string: "")
    let attribute = [NSFontAttributeName: font]
    while mutable.size(attributes: attribute).width < width - (2 * kPadding) {
        mutable.append(" ")
    }
    return mutable as String
}

und jetzt können Sie erstellen UITableViewRowAction.

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let whitespace = whitespaceString(width: kCellActionWidth)
    let deleteAction = UITableViewRowAction(style: .`default`, title: whitespace) { (action, indexPath) in
        // do whatever you want
    }

    // create a color from patter image and set the color as a background color of action
    let kActionImageSize: CGFloat = 34
    let view = UIView(frame: CGRect(x: 0, y: 0, width: kCellActionWidth, height: kCellHeight))
    view.backgroundColor = UIColor.white
    let imageView = UIImageView(frame: CGRect(x: (kCellActionWidth - kActionImageSize) / 2,
                                              y: (kCellHeight - kActionImageSize) / 2,
                                              width: 34,
                                              height: 34))
    imageView.image = UIImage(named: "x")
    view.addSubview(imageView)
    let image = view.image()

    deleteAction.backgroundColor = UIColor(patternImage: image)

    return [deleteAction]
}

Das Ergebnis wird so aussehen.

Geben Sie hier die Bildbeschreibung ein

Eine andere Möglichkeit, dies zu tun, besteht darin, eine benutzerdefinierte Schriftart zu importieren, die das Bild enthält, das Sie als Schriftart verwenden und verwenden möchten UIButton.appearance. Dies wirkt sich jedoch auf andere Schaltflächen aus, sofern Sie die Schriftart anderer Schaltflächen nicht manuell festlegen.

Ab iOS 11 wird diese Meldung angezeigt [TableView] Setting a pattern color as backgroundColor of UITableViewRowAction is no longer supported.. Derzeit funktioniert es noch, aber es würde im zukünftigen Update nicht funktionieren.

==========================================

Für iOS 11+ können Sie Folgendes verwenden:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
  let deleteAction = UIContextualAction(style: .normal, title: "Delete") { (action, view, completion) in
    // Perform your action here
      completion(true)
  }

  let muteAction = UIContextualAction(style: .normal, title: "Mute") { (action, view, completion) in
    // Perform your action here
    completion(true)
  }

  deleteAction.image = UIImage(named: "icon.png")
  deleteAction.backgroundColor = UIColor.red
  return UISwipeActionsConfiguration(actions: [deleteAction, muteAction])
} 

Könnten Sie das func image () -> UIImage {} klären? Ich habe Fehler, da in der ersten Zeile keine varaible bounds.size vorhanden ist. ebenfalls in der 5. Zeile gibt es keine Ebenenvariable ... Da die Funktion keine Variablen aufnimmt. Vielen Dank
Jerland2

1
Das ist eine 'UIView'-Erweiterung. Grenzen sind also die Grenzen der Instanz.
Ryan

Das ist super, genau das, wonach ich gesucht habe. Sehr kreative Umsetzung, liebe es! Vielen Dank
Jerland2

1
Zu Ihrer Information, Sie sollten init nicht direkt verwenden: deleteAction.backgroundColor = UIColor.init(patternImage: image)sollte es sein deleteAction.backgroundColor = UIColor(patternImage: image).
Tolle

Gute Antwort. Danke vielmals!
krlbsk

12

Verweisen Sie auf diesen Link: https://github.com/TeehanLax/UITableViewCell-Swipe-for-Options

Und passen Sie Ihre uitableviewcell mit mehreren Tasten an.

 UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds) + kCatchWidth, CGRectGetHeight(self.bounds));
scrollView.delegate = self;
scrollView.showsHorizontalScrollIndicator = NO;

[self.contentView addSubview:scrollView];
self.scrollView = scrollView;

UIView *scrollViewButtonView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) - kCatchWidth, 0, kCatchWidth, CGRectGetHeight(self.bounds))];
self.scrollViewButtonView = scrollViewButtonView;
[self.scrollView addSubview:scrollViewButtonView];

// Set up our two buttons
UIButton *moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
moreButton.backgroundColor = [UIColor colorWithRed:0.78f green:0.78f blue:0.8f alpha:1.0f];
moreButton.frame = CGRectMake(0, 0, kCatchWidth / 3.0f, CGRectGetHeight(self.bounds));
[moreButton setTitle:@"More" forState:UIControlStateNormal];
[moreButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[moreButton addTarget:self action:@selector(userPressedMoreButton:) forControlEvents:UIControlEventTouchUpInside];

[self.scrollViewButtonView addSubview:moreButton];

UIButton *shareButton = [UIButton buttonWithType:UIButtonTypeCustom];
shareButton.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:1.0f];
shareButton.frame = CGRectMake(kCatchWidth / 3.0f, 0, kCatchWidth / 3.0f, CGRectGetHeight(self.bounds));
[shareButton setTitle:@"Share" forState:UIControlStateNormal];
[shareButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[shareButton addTarget:self action:@selector(userPressedMoreButton:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollViewButtonView addSubview:shareButton];

UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
deleteButton.backgroundColor = [UIColor colorWithRed:1.0f green:0.231f blue:0.188f alpha:1.0f];
deleteButton.frame = CGRectMake(kCatchWidth / 3.0f+kCatchWidth / 3.0f, 0, kCatchWidth / 3.0f, CGRectGetHeight(self.bounds));
[deleteButton setTitle:@"Delete" forState:UIControlStateNormal];
[deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[deleteButton addTarget:self action:@selector(userPressedDeleteButton:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollViewButtonView addSubview:deleteButton];

UIView *scrollViewContentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
scrollViewContentView.backgroundColor = [UIColor whiteColor];
[self.scrollView addSubview:scrollViewContentView];
self.scrollViewContentView = scrollViewContentView;

UILabel *scrollViewLabel = [[UILabel alloc] initWithFrame:CGRectInset(self.scrollViewContentView.bounds, 10, 0)];
self.scrollViewLabel = scrollViewLabel;
[self.scrollViewContentView addSubview:scrollViewLabel];
  • Ich habe diesen Code mit meiner App implementiert und habe ein solches Ergebnis erzielt. Sie können die Anzahl der Schaltflächen in der Wischzelle hinzufügen.

    Hier sind Screenshots implementiert

    Geben Sie hier die Bildbeschreibung einNach dem Wischen erscheinen die Schaltflächen von Zelle 3 mit "Mehr", "Teilen", "Löschen".


10

Sie können dies versuchen,

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

    let backView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
    backView.backgroundColor = #colorLiteral(red: 0.933103919, green: 0.08461549133, blue: 0.0839477703, alpha: 1)

    let myImage = UIImageView(frame: CGRect(x: 30, y: backView.frame.size.height/2-14, width: 16, height: 16))
    myImage.image = #imageLiteral(resourceName: "rubbish-bin")
    backView.addSubview(myImage)

    let label = UILabel(frame: CGRect(x: 0, y: myImage.frame.origin.y+14, width: 80, height: 25))
    label.text = "Remove"
    label.textAlignment = .center
    label.textColor = UIColor.white
    label.font = UIFont(name: label.font.fontName, size: 14)
    backView.addSubview(label)

    let imgSize: CGSize = tableView.frame.size
    UIGraphicsBeginImageContextWithOptions(imgSize, false, UIScreen.main.scale)
    let context = UIGraphicsGetCurrentContext()
    backView.layer.render(in: context!)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    let delete = UITableViewRowAction(style: .destructive, title: "           ") { (action, indexPath) in
        print("Delete")
    }

    delete.backgroundColor = UIColor(patternImage: newImage)

    return [delete, share]
}

6

Dies unterstützt sowohl Titel als auch Bild.

Für iOS 11 und danach:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let action = UIContextualAction(
        style: .normal,
        title: "My Title",
        handler: { (action, view, completion) in
            //do what you want here
            completion(true)
    })

    action.image = UIImage(named: "My Image")
    action.backgroundColor = .red
    let configuration = UISwipeActionsConfiguration(actions: [action])
    configuration.performsFirstActionWithFullSwipe = false
    return configuration
}

Eine ähnliche Methode ist auch für verfügbar leadingSwipeActions

Quelle:

https://developer.apple.com/videos/play/wwdc2017/201/ (Gespräche darüber in ca. 16 Minuten) https://developer.apple.com/videos/play/wwdc2017/204/ (Gespräche darüber um ca. 23 Minuten)


Was ist mit iOS 9 und höher?
Majid Bashir

@MajidBashir Meine Apps unterstützen die älteren iOS-Versionen nicht. Entschuldigung, ich kann nicht helfen.
Vinay Kharb

3

Wenn Sie beim Ausführen von Wischaktionen nur Text verwenden möchten, können Sie die Standard-Wischaktionen von iOS verwenden. Wenn Sie jedoch Bild und Text möchten, müssen Sie ihn anpassen. Ich habe ein großartiges Tutorial und Beispiel gefunden, mit dem dieses Problem behoben werden kann.

Probieren Sie dieses Repository aus, um die benutzerdefinierte Wischzelle zu erhalten. Sie können hier mehrere Optionen hinzufügen.

http://iosbucket.blogspot.in/2016/04/custom-swipe-table-view-cell_16.html

https://github.com/pradeep7may/PKSwipeTableViewCell

Geben Sie hier die Bildbeschreibung ein


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

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

            self.myArray.add(indexPath.row)
        })
        editAction.backgroundColor = UIColor.blue

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

            self.myArray.removeObject(at: indexPath.row)
            self.myTableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)

        })
        deleteAction.backgroundColor = UIColor.red
        // action three
        let shareAction = UITableViewRowAction(style: .default, title: "Share", handler: { (action , indexPath)in
             print("Share Tapped")
        })
        shareAction.backgroundColor = UIColor .green
        return [editAction, deleteAction, shareAction]
    }

wäre schön, wenn du in der antwort selbst eine erklärung hinzufügst kumpel.
Rai

Es würde, aber ich glaube, der Code spricht in diesem Fall für sich selbst (wenn man bedenkt, dass Kommentare enthalten sind und Funktionsnamen ziemlich selbsterklärend sind)
James Wolfe

2
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let delete = UITableViewRowAction(style: .Destructive, title: "Delete") { (action, indexPath) in
        // delete item at indexPath
    }

    let share = UITableViewRowAction(style: .Normal, title: "Disable") { (action, indexPath) in
    // share item at indexPath
    }

    share.backgroundColor = UIColor.blueColor()

    return [delete, share]
}

Der obige Code zeigt, wie Sie benutzerdefinierte Schaltflächen erstellen, wenn Sie über die Zeile streichen.


aber der Schlag hat KEINE Wirkung !! in swift3 Benötigen Sie weitere Methoden?
Mythicalcoder

tableView(_, commit:, forRowAt:) { }wie oben erwähnt
Nyxee

0

Wie ich denke, ist es nicht der beste Weg, UIGestureRecognizer-basierte Zellen zu verwenden.

Erstens haben Sie keine Optionen zur Verwendung von CoreGraphics.

Perfekte Lösung, wird UIResponder oder eine UIGestureRecognizerfür die gesamte Tabellenansicht. Nicht für jeden UITableViewCell. Es wird Sie App stecken lassen.


0

Erstellen Sie eine Ansicht für die benutzerdefinierte Zelle in der Tabellenansicht und wenden Sie PanGestureRecognizer auf die Ansicht für die Zelle an. Fügen Sie die Schaltflächen zur benutzerdefinierten Zelle hinzu. Wenn Sie die Ansicht in der benutzerdefinierten Zelle durchwischen, werden die Schaltflächen in der benutzerdefinierten Zelle angezeigt.

 UIGestureRecognizer* recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    recognizer.delegate = self;
    [YourView addGestureRecognizer:recognizer];

Und behandeln Sie das Schwenken der Ansicht in der Methode

 if (recognizer.state == UIGestureRecognizerStateBegan) {
    // if the gesture has just started, record the current centre location
    _originalCenter = vwCell.center;
}

// 2
if (recognizer.state == UIGestureRecognizerStateChanged) {
    // translate the center
    CGPoint translation = [recognizer translationInView:self];
    vwCell.center = CGPointMake(_originalCenter.x + translation.x, _originalCenter.y);
    // determine whether the item has been dragged far enough to initiate  / complete
    _OnDragRelease = vwCell.frame.origin.x < -vwCell.frame.size.width / 2;

}

// 3
if (recognizer.state == UIGestureRecognizerStateEnded) {
    // the frame this cell would have had before being dragged
    CGPoint translation = [recognizer translationInView:self];

    if (_originalCenter.x+translation.x<22) {
          vwCell.center = CGPointMake(22, _originalCenter.y);
        IsvwRelease=YES;

    }
    CGRect originalFrame = CGRectMake(0, vwCell.frame.origin.y,
                                      vwCell.bounds.size.width, vwCell.bounds.size.height);
    if (!_deleteOnDragRelease) {
        // if the item is not being dragged far enough , snap back to the original location
        [UIView animateWithDuration:0.2
                         animations:^{
                             vwCell.frame = originalFrame;
                         }
         ];
    }
}

Haben Sie ein Beispiel
Maulik Shah

0
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIContextualAction *delete = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:nil handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
        
        // your code...
        
    }];
    delete.image  = [UIImage systemImageNamed:@"trash"];
    
    UISwipeActionsConfiguration *actions = [UISwipeActionsConfiguration configurationWithActions:[[NSArray alloc] initWithObjects:delete, nil]];
    
    return actions;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.