스 와이프하여 삭제하고 '더보기'버튼 (iOS 7의 Mail 앱과 유사)


사용자가 표보기에서 셀을 스 와이프 할 때 "more (추가)"버튼을 만드는 방법 (예 : 7의 메일 앱)

나는 여기와 코코아 터치 포럼에서이 정보를 찾고 있었지만 대답을 찾지 못했고 나보다 똑똑한 사람이 나에게 해결책을 줄 수 있기를 바라고있다.

나는 사용자가 테이블 뷰 셀을 스 와이프 할 때 하나 이상의 편집 버튼 (기본값은 삭제 버튼)을 표시하기를 원합니다. iOS 7 용 Mail 앱에서는 스 와이프하여 삭제할 수 있지만 표시되는 'MORE (추가)'버튼이 있습니다.



Answers



나는 iOS 8 메일 앱과 같은 다양한 전환과 확장 가능한 버튼을 지원하는 swippable 버튼을 구현하는 새로운 라이브러리를 만들었습니다.

https://github.com/MortimerGoro/MGSwipeTableCell

이 라이브러리는 UITableViewCell을 만드는 다양한 방법과 호환되며 iOS 5, iOS 6, iOS 7 및 iOS 8에서 테스트되었습니다.

여기에 몇 가지 전환 샘플이 있습니다.

테두리 전환 :

클립 전환

3D 전환 :




구현 방법

iOS 8이이 API를 여는 것처럼 보입니다. 이러한 기능에 대한 힌트는 Beta 2에 있습니다.

무언가를 작동 시키려면 UITableView의 델리게이트에 다음 두 가지 메소드를 구현하여 원하는 효과를 얻으십시오 (예를 들어 gist 참조).

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


알려진 문제점

설명서 tableView : commitEditingStyle : forRowAtIndexPath 말한다 :

"UITableViewRowAction을 사용하여 편집 작업을 수행하지 않아도됩니다. 대신 액션의 핸들러가 호출됩니다."

그러나 스 와이프는 스 와이프 없이는 작동하지 않습니다. 메소드 스텁이 비어 있더라도 여전히 필요합니다. 이것은 베타 2에서 가장 명백한 버그입니다.


출처

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

원본 답변 : https://.com/a/24540538/870028


최신 정보:

이 작동 방식의 샘플 코드 (In Swift) : http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip

샘플 코드에는 MasterViewController.swift에서 이처럼 쉽게 따라 할 수있는 메서드가 포함되어 있습니다.이 메서드를 사용하면 OP 스크린 샷에 표시된 동작을 얻을 수 있습니다.

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



구현 방법

iOS 8이이 API를 열었습니다.

이 작업을하려면 UITableView의 위임에 다음 두 가지 메소드를 구현하여 원하는 효과를 얻으십시오 (예를 들어 코드 참조).

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


알려진 문제점

UITableView.h 파일은 tableView 에 관해 다음과 같이 말합니다 . commitEditingStyle : forRowAtIndexPath :

"UITableViewRowAction을 사용하여 편집 작업을 수행하지 않아도됩니다. 대신 액션의 핸들러가 호출됩니다."

그러나 스 와이프는 스 와이프 없이는 사용할 수 없습니다. 이것은 버그 인 것 같습니다.


출처

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


샘플 코드 :

이것은 기본 Master-Detail Application 템플릿 (Swift에 있음)을 기반으로합니다 : http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip




Johnny의 대답은 upvote에 적합한 것이다. 나는 이것을 객관적 -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...
    }



이것은 개인용 API입니다 (다소 말도 안되게).

다음 두 메서드는 private이며 UITableView의 대리자에게 전송됩니다.

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

그들은 꽤 자명하다.




사과가 당신에게 필요한 것을 줄 때까지 기다릴 수 없길 바래요? 그래서 여기 내 선택이 있습니다.

사용자 지정 셀을 만듭니다. 두 개의 uiview가 있습니다.

1. upper
2. lower

아래쪽보기에서 필요한 버튼을 추가하십시오. 다른 IBActions와 마찬가지로 행동을 취하십시오. 애니메이션 시간, 스타일 및 기타 사항을 결정할 수 있습니다.

이제 상단보기에 uiswipegesture를 추가하고 스 와이프 제스처에 대한 하단 뷰를 표시합니다. 나는 내가 이것을 염려하는 한 가장 단순한 선택을하기 전에 이것을했다.

희망 그 도움.




Johnny의 답변을 향상시키기 위해 이제 다음과 같이 공용 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];
}



이는 표준 SDK를 사용하여 불가능합니다. 그러나 Mail.app에서 동작을 모방하는 다양한 타사 솔루션이 있습니다. 그 중 일부 (예 : MCSwipeTableViewCell , DAContextMenuTableViewController , RMSwipeTableViewCell )는 제스처 인식기를 사용하여 스 와이프를 감지합니다. 예를 들어 SWTableViewCell 은 두 번째 UISScrollView를 표준 UITableViewCellScrollView ( UITableViewCellScrollView 개인 하위 뷰) 아래에 배치하고 일부는 UITableViewCellScrollView 의 동작을 수정합니다.

터치 핸들링이 가장 자연스러운 느낌을받은 이후 가장 마지막 접근 방식을 좋아합니다. 특히, MSCMoreOptionTableViewCell 이 좋습니다. 사용자의 선택에 따라 선택 사항이 달라질 수 있습니다 (왼쪽에서 오른쪽으로 팬이 필요한지 여부, iOS 6 호환성이 필요한지 여부 등). 또한 이러한 접근 방식의 대부분은 부담을 안겨줍니다. Apple이 UITableViewCell 하위 뷰 계층 구조를 변경하면 향후 iOS 버전에서 쉽게 깨질 수 있습니다.




사용자가 willTransitionToState:(UITableViewCellStateMask)state 할 때마다 호출되는 UITableViewCell 및 하위 클래스 메서드 willTransitionToState:(UITableViewCellStateMask)state 를 하위 클래스화해야합니다. state 플래그는 삭제 버튼이 표시되는지 알려주고 거기에 기타 버튼을 표시하거나 숨 깁니다.

불행히도이 메서드는 삭제 단추의 폭이나 애니메이션 시간을 제공하지 않습니다. 따라서 More 버튼의 프레임과 애니메이션 시간을 코드로 관찰하고 하드 코딩해야합니다 (개인적으로 Apple이 이에 대해 뭔가를해야한다고 생각합니다).




모든 라이브러리를 사용하지 않고 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]
    }

}



신속한 프로그래밍

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
}



이게 당신을 도와 줄 수 있습니다.

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



내 응용 프로그램에 동일한 기능을 추가하려고했고 많은 다른 자습서 ( raywenderlich 가 최고의 DIY 솔루션 임)를 거친 후 Apple에 자체 UITableViewRowAction 클래스가 있다는 것을 알았습니다.이 클래스는 매우 편리합니다.

Tableview의 보일러 점 메서드를 다음과 같이 변경해야합니다.

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은 style 속성의 값을 기반으로 기본 색상을 지정합니다.

iOS 8.0 이상에서 사용할 수 있습니다.

버튼의 글꼴을 변경하려면 좀 더 까다 롭습니다. 나는 다른 게시물 을 보았습니다. 코드뿐만 아니라 링크를 제공하기 위해 여기에 사용 된 코드가 있습니다. 단추의 모양을 변경해야합니다. 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];
}

빠른:

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

이것은 가장 쉽고, 가장 stream-lined 버전 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 답변

이것은 당신이 필요로하는 유일한 기능입니다. 사용자 지정 작업에 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]
}



개인용 API를 포함하지 않거나 자체 시스템을 구성하지 않는 다소 취약한 방식입니다. 당신은 당신의 베팅을 헤지하고있다. 애플이이를 깨뜨리지 않는다는 것이고,이 몇 줄의 코드를 대체 할 수있는 API를 공개하기를 희망한다.

  1. KVO self.contentView.superview.layer.sublayer. init에서 이것을하십시오. 이것은 UIScrollView의 레이어입니다. KVO '하위보기'를 할 수 없습니다.
  2. 하위보기가 변경되면 scrollview.subview 내의 삭제 확인보기를 찾으십시오. 이는 관찰 콜백에서 수행됩니다.
  3. 해당 뷰의 크기를 두 배로하고 유일한 하위 뷰의 왼쪽에 UIButton을 추가합니다. 이는 observe 콜백에서도 수행됩니다. 삭제 확인보기의 유일한 하위 뷰는 삭제 버튼입니다.
  4. (선택 사항) UIButton 이벤트는 UITableView를 발견 할 때까지 self.superview를 조회 한 다음 사용자가 작성한 데이터 소스 또는 위임 메소드 (예 : tableView : commitCustomEditingStyle : forRowAtIndexPath :)를 호출해야합니다. [tableView indexPathForCell : self]를 사용하여 셀의 indexPath를 찾을 수 있습니다.

또한 표준 테이블 뷰 편집 대리자 콜백을 구현해야합니다.

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



라는 놀라운 라이브러리가 SwipeCellKit더 승인을 획득해야한다. 제 생각에는이보다 더 시원하다 MGSwipeTableCell. 후자는 완전히 반면 메일 응용 프로그램의 세포의 행동을 복제하지 않습니다 SwipeCellKit수행합니다. 보라




아이폰 OS (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;

문서 도구 : https://developer.apple.com/documentation/uikit/uitableviewdelegate/2902367-tableview?language=objc




다음은 하나 개의 단순한 솔루션이다. 표시하고있는 UITableViewCell 내부 사용자 정의에 UIView를 숨길 수있다. 논리를 표시하는있는 UITableViewCell, BaseTableViewCell에서 확장 클래스 내부에 포함되어 있습니다.

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

이 기능을 얻으려면, 단순 BaseTableViewCell에서 테이블 뷰 셀을 확장합니다.

다음으로, UITableViewDelegate를 구현 내부의 UIViewController는 왼쪽과 오른쪽 스 와이프를 처리하기 위해 두 개의 제스처 인식기를 만듭니다.

- (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의로드의이 방법은 예입니다. 당신이 원하는대로 그것을 관리 할 수 ​​있습니다.




스위프트 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
}



스위프트 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])
}