Проведите по удалению и нажмите кнопку «Дополнительно» (например, в приложении «Почта» на iOS 7)

Как создать кнопку «больше», когда пользователь протаскивает ячейку в виде таблицы (например, почтовое приложение в iOS 7)

Я искал эту информацию как здесь, так и на форуме Cocoa Touch, но я не могу найти ответ, и я надеюсь, что кто-то умнее меня сможет дать мне решение.

Я бы хотел, чтобы пользователь просматривал ячейку таблицы, чтобы отображать несколько кнопок редактирования (по умолчанию это кнопка удаления). В приложении Mail для iOS 7 вы можете прокручивать, чтобы удалить, но есть кнопка «БОЛЬШЕ», которая появляется.

enter image description here

233
Проверьте это: teehanlax.com/blog/reproducing- the-ios-7-mail-apps-interface и моя реализация с использованием autolayout github.com/Jafared/ JASwipeCellExperiment
добавлено автор Alexis, источник
добавлено автор null, источник
с iOS 11 это возможно без стороннего кода. прокрутите вниз для моего ответа
добавлено автор Lewis42, источник
@GuyKahlonMatrix благодарит за решение, которое оно работает как шарм. Этот вопрос является результатом №1 во многих поисковых системах Google, и люди вынуждены обмениваться своими знаниями с помощью комментариев, потому что какой-то парень решил, что более полезно закрыть вопрос и проповедовать демократию. Это место явно нуждается в улучшенных моделях.
добавлено автор Şafak Gezer, источник
Если вы можете настроить iOS 8, мой ответ ниже будет тем, что вы хотите.
добавлено автор Johnny, источник
@ ŞafakGezer Как установить ширину кнопок rowEditActionButtons
добавлено автор ArgaPK, источник
@MonishBansal Bansal Похож на кого-то в этой теме ( devforums.apple.com/message/860459#860459 на форуме разработчиков Apple) пошли вперед и построили собственную реализацию. Вы можете найти проект, который делает то, что вы хотите в GitHub: github.com/daria-kopaliani/DAContextMenuTableViewCont‌ ролик
добавлено автор Guy Kahlon, источник
Чтобы добавить кнопку «Удалить», я реализую следующие две функции. - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath; - (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editStyle forRowAtIndexPath: (NSIndexPath *) indexPath; И я хочу добавить к нему кнопку «Больше».
добавлено автор Guy Kahlon, источник
Я думаю, что этот учебник может помочь: raywenderlich.com/62435/…
добавлено автор César Abreu, источник

20 ответы

Как реализовать

Похоже, что iOS 8 открывает этот API. Указания на такую ​​функциональность присутствуют в бета-версии 2.

Чтобы получить что-то работающее, выполните следующие два метода для вашего делегата UITableView, чтобы получить желаемый эффект (см. Пример для примера).

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


Известные вопросы

В документации указано tableView: commitEditingStyle: forRowAtIndexPath:

«Не вызывается для действий редактирования с помощью UITableViewRowAction - вместо этого будет вызываться обработчик действия."

Однако прокрутка не работает без него. Даже если заглушка метода пуста, она все еще нуждается в ней, пока. Это, скорее всего, ошибка в бета-версии 2.


источники

https://twitter.com/marksands/status/481642991745265664 https://gist.github.com/marksands/76558707f583dbb8f870

Original Answer: https://stackoverflow.com/a/24540538/870028


Обновить:

Sample code with this working (In Swift): http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip

Код примера содержит этот простой в использовании метод в MasterViewController.swift, и только с помощью этого метода вы получите поведение, показанное на снимке экрана:

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];
}
122
добавлено
Огромное спасибо. :) Ваш ответ мне очень помог
добавлено автор Somu, источник
Кажется, что обработчики вызываются, но после этого ячейка не закрывается. Упускаю ли я очевидный способ сделать это? Вызов endEditing: в представлении таблицы, похоже, ничего не делает.
добавлено автор Ben Lachman, источник
Чтобы ответить на мои собственные комментарии. Вы вызываете tableView.editing = false ( NO в objc), и ячейка «закрывается».
добавлено автор Ben Lachman, источник
Я не работаю в объективном c .. Тот же код, который я написал. пожалуйста, предложите несколько советов.
добавлено автор Solid Soft, источник
сделали это. Но не знаю, почему это произошло. Он работает со мной в UITableViewController, а не в UITableView, который находится внутри UIViewController.
добавлено автор Solid Soft, источник
@Johnny Да, я упомянул. Теперь работаю унаследовать UITableViewController и работал. Спасибо за поддержку.
добавлено автор Solid Soft, источник
Как добавить значок вместо текста? Я не хочу удалять текст, просто хочу значок удаления. Как добиться этого быстрым? Пожалуйста помоги
добавлено автор Alok Nair, источник
Если бы я мог видеть этот ответ, прежде чем погрузиться в сложную реализацию перед iOS 8!
добавлено автор fujianjin6471, источник
Это может показаться чересчур простым, но я просто хочу убедиться в том, что основы были покрыты. Соответствует ли ваш UIViewController протоколу UITableViewDelegate? Если да, назначаете ли вы его self.tableView.delegate = self; (или еще что-то)?
добавлено автор Johnny, источник
@Siegfoult Пробовали ли вы реализовать (даже если оставили пустой) tableView: commitEditingStyle: forRowAtIndexPath :?
добавлено автор Johnny, источник
@SolidSoft У вас есть пример проекта, на который я мог бы смотреть? Я мог бы помочь лучше.
добавлено автор Johnny, источник
@SolidSoft К сожалению, я забыл пометить вас.
добавлено автор Johnny, источник
Кажется, это правильно, но в Xcode 6 GM жест жестов не работает. Доступ к редактированию по-прежнему возможен, поместив представление таблицы в режим редактирования. Кто-нибудь еще найдет, что салфетка не работает?
добавлено автор Siegfoult, источник
Хорошая информация
добавлено автор Gabox, источник

Я создал новую библиотеку для реализации swippable кнопок, которая поддерживает множество переходов и расширяемых кнопок, таких как почтовое приложение iOS 8.

https://github.com/MortimerGoro/MGSwipeTableCell

Эта библиотека совместима со всеми различными способами создания UITableViewCell и ее тестирования на iOS 5, iOS 6, iOS 7 и iOS 8.

Здесь образец некоторых переходов:

Переход границы:

Border transition

Переход клипа

Переход клипа

3D-переход:

enter image description here

117
добавлено
Это потрясающая библиотека, и очень хорошо, что она по-прежнему поддерживается.
добавлено автор confile, источник
Отличная работа! Было бы замечательно иметь обратные вызовы для настройки анимации.
добавлено автор Pacu, источник
@MortimerGoro Хороший человек работы. Выглядит хорошо. Я пытаюсь реализовать аналогичный эффект в одном из моих Android-проектов. Скажите, пожалуйста, как я могу добиться этого в Android?
добавлено автор Nitesh Khatri, источник
Также есть некоторые проблемы с VoiceOver с этой настройкой. Это замечательная работа в противном случае!
добавлено автор Kane Cheshire, источник
Ничего себе, серьезно впечатляющая работа!
добавлено автор Ben Williams, источник
Это довольно плохой почерк. Просто здорово, спасибо!
добавлено автор 0yeoj, источник
на iOS 8 + iPad, я просто не получаю салфетки.
добавлено автор ScorpionKing2k5, источник
@MortimerGoro, я пробовал с «MGSwipeTableCel» l framework, но проблема в том, когда я перезагружаю таблицу, а затем салфеткой скрыта. Любая работа вокруг этой проблемы.
добавлено автор Ganesh Guturi, источник
Удивительно!!! Просто мимо, но не может голосовать за фантастические анимации !!!
добавлено автор Z.pyyyy, источник
Отличная работа! Это очень помогает мне и сэкономило много времени.
добавлено автор Moin Uddin, источник

Ответ Джонни - это правильный вариант для продвижения. Я просто добавляю это ниже в цель-c, чтобы сделать его понятным для новичков (и тех из нас, кто отказывается изучать синтаксис Swift :)

Убедитесь, что вы объявили uitableviewdelegate и имеете следующие методы:

 -(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
добавлено
важно отметить canEditRowAtIndexPath
добавлено автор Heckscheibe, источник
Если я перезагружаю таблицу после прокрутки ячейки, то эти кнопки прокрутки видны или скрыты?
добавлено автор Ganesh Guturi, источник

Это (довольно смешно) частный API.

Следующие два метода являются частными и отправляются делегату UITableView:

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

Они довольно понятны.

25
добавлено
Apple открыла эту функцию с iOS 8. См. Ответ Джонни ниже.
добавлено автор Siegfoult, источник

Чтобы улучшить ответ Джонни, теперь это можно сделать с помощью общедоступного API следующим образом:

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
добавлено
Не могли бы вы обновить код до Swift 3? благодаря
добавлено автор bibscy, источник
спасибо, работая отлично.
добавлено автор Shahbaz Akram, источник

Надеюсь, вы не можете дождаться, пока яблоко даст вам все, что вам нужно? Итак, вот мой вариант.

Создайте пользовательскую ячейку. У вас есть два uiviews

1. upper
2. lower

В нижнем окне добавьте нужные вам кнопки. Выполните свои действия только     как и любые другие IBActions. вы можете определить время анимации, стиль и что угодно.

теперь добавьте uiswipegesture в верхний вид и покажите свой нижний вид на жестов салфетки. Я сделал это раньше, и это самый простой вариант, насколько мне известно.

Надеюсь, что это поможет.

17
добавлено

Это невозможно с использованием стандартного SDK. Однако существуют различные сторонние решения, которые более или менее имитируют поведение в Mail.app. Некоторые из них (например, MCSwipeTableViewCell , DAContextMenuTableViewController , RMSwipeTableViewCell ) обнаруживает удары с помощью распознавателей жестов, некоторые из них (например, SWTableViewCell ) помещают второй UISScrollView под стандартный UITableViewCellScrollView ( private subview UITableViewCell ), а некоторые из них изменяют поведение UITableViewCellScrollView .

Мне нравится последний подход, поскольку сенсорная обработка кажется наиболее естественной. В частности, хороший MSCMoreOptionTableViewCell . Ваш выбор может зависеть от ваших конкретных потребностей (нужен ли вам левый-правый кастрюля, нужна ли вам совместимость с iOS 6 и т. Д.). Также имейте в виду, что большинство из этих подходов связано с бременем: они могут легко ломаться в будущей версии iOS, если Apple вносит изменения в иерархию подкатегорий UITableViewCell .

7
добавлено

Код версии Swift 3 без использования библиотеки:

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
добавлено

Вам нужно подклассифицировать UITableViewCell и подкласс метод willTransitionToState: (UITableViewCellStateMask) состояние , которое вызывается всякий раз, когда пользователь просматривает ячейку. Флаги state сообщают вам, отображается ли кнопка «Удалить» и отображаются/скрываются кнопка «Дополнительно».

Unfortunately this method gives you neither the width of the Delete button nor the animation time. So you need to observer & hard-code your More button's frame and animation time into your code (I personally think Apple needs to do something about this).

6
добавлено
«Я лично считаю, что Apple должна что-то сделать». Согласен. Вы уже писали им сообщение об ошибке/запрос функции?
добавлено автор Tafkadasoh, источник

Для быстрого программирования

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
добавлено
@bibscy вы можете предложить редактировать. Не использовали swift в течение длительного времени, поэтому не уверен, какой правильный синтаксис
добавлено автор Michael Yagudaev, источник
Не могли бы вы обновить код для Swift 3?
добавлено автор bibscy, источник

Начиная с iOS 11 это общедоступно в UITableViewDelegate . Вот пример кода:

- (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;
}

Так же доступно:

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

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

3
добавлено

Я хотел добавить такую ​​же функциональность в свое приложение, и после прохождения множества различных учебников ( raywenderlich - лучшее решение для DIY), я узнал, что у Apple есть свой собственный UITableViewRowAction класс, который очень удобно.

Вы должны изменить метод Catpoint для таблицы Viewview:

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

Вы можете узнать об этом больше на Этот сайт . Apple собственная документация действительно полезно для изменения цвета фона:

Цвет фона кнопки действия.

     

Декларацияobjective-c@property (неатомная, копия) UIColor   * backgroundColor Обсуждение Используйте это свойство, чтобы указать цвет фона для вашей кнопки. Если вы не укажете значение для   это свойство, UIKit присваивает цвет по умолчанию, основанный на значении в   стиль.

     

Доступность Доступна в iOS 8.0 и более поздних версиях.

Если вы хотите изменить шрифт кнопки, это немного сложнее. Я видел другое сообщение на SO. Ради обеспечения кода, а также ссылки, вот код, который они использовали там. Вам придется изменить внешний вид кнопки. Вам нужно будет сделать конкретную ссылку на tableviewcell, иначе вы измените внешний вид кнопки во всем приложении (я этого не хотел, но вы можете, я не знаю :))

Цель 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];
}

Swift:

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

Это самая простая и самая поточная версия IMHO. Надеюсь, поможет.

Обновление: вот версия Swift 3.0:

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 Не могли бы вы обновить свой код до Swift 3? shareMenu. не принимает метод addAction . благодаря
добавлено автор bibscy, источник
@bibscy Я добавил быструю версию. Вам нужен бит для атрибута? sharemenu - это просто UIAlertController, поэтому он должен принять меры. Попробуйте и дайте мне знать, если удача :)
добавлено автор Septronic, источник
@GuyKahlon да, вы абсолютно правы в отношении проблемы с левым и правым салфеткой, и я согласен, что для большей настройки MGSwipeTableCell является лучшим. Сам Apple не самый сложный вариант, но я нашел его наиболее простым для простых задач.
добавлено автор Septronic, источник
Спасибо за ваш ответ, я уверен, что это поможет многим разработчикам. Да, вы правы, на самом деле Apple предоставляет это решение от iOS 8. Но, к сожалению, это собственное решение не обеспечивает полную функциональность. Например, в приложении Apple's Mail у вас есть кнопки с двух сторон (одна кнопка с левой стороны и три справа) с текущим API от Apple, вы не можете добавлять кнопки с обеих сторон, а также текущий API не поддерживает действие по умолчанию, когда пользователь салфет долго с каждой стороны. Лучшим решением для IMHO является open source MGSwipeTableCell.
добавлено автор Guy Kahlon, источник

Фактический Swift 3 Ответ

Это ТОЛЬКО функция, в которой вы нуждаетесь. Для пользовательских действий вам не нужны функции CanEdit или CommitEditingStyle.

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
добавлено

ЭТО МОЖЕТ ПОМОЧЬ ВАМ.

-(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
добавлено

There is an amazing library called SwipeCellKit, it should gain more acknowledgement. In my opinion it is cooler than MGSwipeTableCell. The latter doesn't completely replicate the behavior of the Mail app's cells whereas SwipeCellKit does. Have a look

1
добавлено
@ horseshoe7 это странно. Я никогда не сталкивался с каким-либо исключением при использовании SwipeCellKit. В конце концов, какое отношение может иметь ячейка к такому исключению, которое происходит из-за изменений в источнике данных?
добавлено автор Andrey Chernukha, источник
Я опробовал SwipeCellKit и был впечатлен ... пока не получил одно из этих Исключений, потому что количество строк перед обновлением табличного представления было не таким же, как после обновления +/- изменение в строках. Дело в том, что я никогда не менял свой набор данных. Так что если это не беспокоит, я не знаю, что это. Поэтому я решил не использовать его и просто использовал новые методы UITableViewDelegate. Если вам нужна дополнительная настройка, вы всегда можете переопределить willBeginEditingRowAt: ....
добавлено автор horseshoe7, источник

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])
}
1
добавлено

Вот несколько хрупкий способ сделать это, который не включает частные API или создание вашей собственной системы. Вы хеджируете свои ставки, что Apple не нарушает этого, и, надеюсь, они выпустят API, который вы можете заменить этими несколькими строками кода.

  1. KVO self.contentView.superview.layer.sublayer. Do this in init. This is the UIScrollView's layer. You can't KVO 'subviews'.
  2. When subviews changes, find the delete confirmation view within scrollview.subviews. This is done in the observe callback.
  3. Double the size of that view and add a UIButton to the left of its only subview. This is also done in the observe callback. The only subview of the delete confirmation view is the delete button.
  4. (optional) The UIButton event should look up self.superview until it finds a UITableView and then call a datasource or delegate method you create, such as tableView:commitCustomEditingStyle:forRowAtIndexPath:. You may find the indexPath of the cell by using [tableView indexPathForCell:self].

Это также требует, чтобы вы выполняли обратные вызовы делегатов стандартного редактирования таблицы.

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 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, источник
Я очень рад, если вы можете предоставить образец кода, спасибо
добавлено автор Guy Kahlon, источник
Спасибо за помощь
добавлено автор Guy Kahlon, источник

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
}
0
добавлено
что такое исходное представление в ваших кодах? это значок или изображение?
добавлено автор Saeed Rahmatolahi, источник

Вот одно простое решение. Он способен отображать и скрывать пользовательский UIView внутри UITableViewCell. Отображение логики содержится внутри класса, расширенного из UITableViewCell, BaseTableViewCell.

BaseTableViewCell.h

#import 

@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

Чтобы получить эту функциональность, просто расширьте ячейку просмотра таблицы из BaseTableViewCell.

Следующий, Внутри UIViewController, которые реализуют UITableViewDelegate, создайте два распознавателя жестов для обработки левого и правого штрихов.

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

Затем добавьте два обработчика салфетки

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

Теперь, внутри cellForRowAtIndexPath, UITableViewDelegate, вы можете создать пользовательский UIView и прикрепить его к выделенной ячейке.

-(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;
}

Конечно, этот способ загрузки пользовательского UIView предназначен именно для этого примера. Управляйте им, как хотите.

0
добавлено

Я использовал tableViewCell , чтобы показать несколько данных, после прокрутки() справа налево в ячейке отобразятся две кнопки Approve And reject, есть два метода: первый - ApproveFunc, который принимает один аргумент, и другой - RejectFunc, который также принимает один аргумент.

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)
    }
0
добавлено
Благодарим вас за этот фрагмент кода, который может предоставить некоторую ограниченную немедленную помощь. Правильное объяснение значительно улучшит его долгосрочную ценность , показав why , это хорошее решение к проблеме, и сделает ее более полезной для будущих читателей с другими аналогичными вопросами. отредактируйте свой ответ, чтобы добавить какое-то объяснение, включая сделанные вами предположения.
добавлено автор Tim, источник
Можете ли вы добавить какое-то объяснение к своему ответу, чтобы читатель мог учиться на нем?
добавлено автор Nico Haase, источник
Mobile Dev Jobs — вакансии и аналитика
Mobile Dev Jobs — вакансии и аналитика
6 187 участник(ов)

Публикуем вакансии и запросы на поиск работы по направлению iOS, Android, Xamarin и т.д. ВАЖНО: Правила публикации и правила канала: Ссылка – https://telegra.ph/Pravila-oformleniya-vakansij-i-rezyume-11-09-2

iOS Developers — русскоговорящее сообщество
iOS Developers — русскоговорящее сообщество
2 400 участник(ов)

Общаемся на темы, посвященным iOS-разработке, Swift, Objective-C, SDK, Rx, Cocoa и т.д.