Спеціальний режим редагування в UITableViewCell, проводячи пальцем ліворуч. Objective-C або Swift


75

Як створити власний режим редагування в iOS7 UITableView за допомогою Objective C, наприклад Evernote або додатку Apple Reminders, провівши пальцем ліворуч. Я намагався встановити користувальницький редагуючийАксесорний Перегляд, але це не спрацювало.

Вид редагування Evernote:

введіть тут опис зображення Вид редагування нагадувань:

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

Мій поточний код -

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

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

Я намагався вирішити проблему за допомогою: (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;
}

І те саме з: (UITableViewCell)

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

чи можемо ми встановити висоту для бічних кнопок? наприклад: моя комірка 150, і я хочу, щоб кнопка відображала лише 50.0f, чи можливо це?
Suhas Arvind Patil

Відповіді:


99

Просто скопіюйте вставний код нижче!

-(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
Щоб вони відображались у моєму випадку, мені також потрібно було реалізувати метод dataSource подання таблиці - (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) Навіть порожньої реалізації цього методу було достатньо, щоб кнопки відображалися.
u2Fan

Я перетворив це на Свіфт і розмістив як нову відповідь нижче. stackoverflow.com/a/33748345/470879
MattyG

@sohil яке зображення? у вас є зображення в камері? Отже, ви отримуєте обробник у тому методі, який я написав, який буде викликаний при натисканні на будь-яку з кнопок
Kartik 123

Це не намагається відповісти на питання. Заявник спеціально запитав, як встановити піктограми для дій пальцем замість тексту.
mattsson

@mattsson, питання в цьому плані невизначене, і ікони взагалі не згадуються. У якості прикладів він згадує Evernote та Apple Reminders. Додаток Apple Reminders використовує стандартну реалізацію, подібну до цієї відповіді.
MattyG

44

Стрімкий 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]
}

Свіфт 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]
}

Примітка: для iOS 8 і новіших версій


swift 3 - Проведення, здається, не працює !! Варіанти не показані !!
mythicalcoder

@Maven, ти реалізував canEditRowAtIndexPath, щоб повернути true?
MattyG

1
Я помітив, що вам також потрібно принаймні писати, func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { }або editActionsForRowAtIndexPathвас не викликатимуть
повторне використання

1
як додати зображення замість тексту?
січня

Чи не відбувається витік пам'яті, коли ви створюєте закриття, на яке посилаються self?
Легонафтик"

24

Ви можете використовувати UITableViewRowAction's backgroundColorдля встановлення власного зображення або перегляду. Фокус у використанні UIColor(patternImage:).

В основному ширина UITableViewRowActionобласті визначається її заголовком, тому ви можете знайти точну довжину заголовка (або пробіли) і встановити точний розмір зображення за допомогою patternImage.

Для реалізації цього я зробив UIViewметод розширення '.

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

і зробити рядок із пробілами та точною довжиною,

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
}

і тепер ви можете творити 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]
}

Результат буде виглядати так.

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

Інший спосіб зробити це - імпортувати спеціальний шрифт, який містить зображення, яке ви хочете використовувати як шрифт та використовувати UIButton.appearance. Однак це вплине на інші кнопки, якщо ви вручну не встановите шрифт іншої кнопки.

З iOS 11 він покаже це повідомлення [TableView] Setting a pattern color as backgroundColor of UITableViewRowAction is no longer supported.. На даний момент він все ще працює, але не буде працювати в майбутньому оновленні.

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

Для iOS 11+ ви можете використовувати:

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

Не могли б ви уточнити зображення func () -> UIImage {} У мене є помилки, оскільки в першому рядку немає змінної bounds.size. так само в 5-му рядку немає змінної шару ... Оскільки функція не приймає жодних змінних. Дякую
Jerland2,

1
Це розширення "UIView". Тож межі будуть межами екземпляра.
Райан

ЦЕ ДИВО, саме те, що я шукав. Дуже креативна реалізація, любіть! Дякую
Jerland2,

1
FYI, ви не повинні використовувати init безпосередньо: deleteAction.backgroundColor = UIColor.init(patternImage: image)має бути deleteAction.backgroundColor = UIColor(patternImage: image). Дивовижна відповідь
TheCodingArt

Чудова відповідь. Дуже дякую!
krlbsk

12

Перейдіть за цим посиланням: https://github.com/TeehanLax/UITableViewCell-Swipe-for-Options

І налаштуйте ваш uitableviewcell за допомогою декількох кнопок.

 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];
  • Я застосував цей код за допомогою мого додатка, який отримав такий результат. Ви можете додати номер кнопки в комірці, що проводить пальцем.

    Тут реалізовані знімки екрану

    введіть тут опис зображенняПісля проведення пальцем по клітинці 3 з’являються кнопки «Ще», «Поділитися», «Видалити».


11

Ви можете спробувати це,

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

Це підтримує як заголовок, так і зображення.

Для iOS 11 і пізніших версій:

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
}

Крім того, подібний метод доступний для leadingSwipeActions

Джерело:

https://developer.apple.com/videos/play/wwdc2017/201/ (Розмови про це приблизно 16 хвилин) https://developer.apple.com/videos/play/wwdc2017/204/ (Розмови про це приблизно 23 хв. часу)


як щодо iOS 9 та новіших версій?
Маджид Башир

@MajidBashir Мої програми не підтримують старіші версії iOS. На жаль, не можу допомогти.
Віней Харб,

3

Якщо ви хочете використовувати лише текст, виконуючи дії по проведенню пальця, тоді ви можете використовувати дії по проведенню пальців iOS за замовчуванням, але якщо ви хочете зображення та текст, вам доведеться їх налаштувати. Я знайшов чудовий підручник та зразок, який може вирішити цю проблему.

Спробуйте це сховище, щоб отримати спеціальну комірку для проведення пальцем. Ви можете додати кілька варіантів тут.

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

https://github.com/pradeep7may/PKSwipeTableViewCell

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


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

було б непогано, якби ви додали якесь пояснення у саму відповідь, приятель.
Рай,

Було б, але я вважаю, що в даному випадку код говорить сам за себе (враховуючи коментарі, а імена функцій досить пояснювальні)
Джеймс Вулф,

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

Наведений вище код показує, як створити власні кнопки під час проведення пальцем по рядку.


але розмах НЕ має ніякого ефекту !! in swift3 Будь-які інші потрібні методи?
mythicalcoder

tableView(_, commit:, forRowAt:) { }як згадувалося вище
nyxee

0

Як я думаю, це не найкращий спосіб використовувати комірки на основі UIGestureRecognizer.

По-перше, у вас не буде можливості використовувати CoreGraphics.

Ідеальне рішення - UIResponder або одне UIGestureRecognizerдля перегляду цілої таблиці. Не для кожного UITableViewCell. Це змусить вас застрягти в додатку.


0

створіть подання на користувацьку комірку в поданні таблиці та застосуйте PanGestureRecognizer до подання на комірку. Додайте кнопки до користувацької комірки, коли ви проводите пальцем по користувацькій комірці, тоді кнопки на користувацькій комірці будуть видимими.

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

І обробляйте панорамування на поданні у методі

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

у вас є приклад
Маулік-шах

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.