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



Answers

구현 방법

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://stackoverflow.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];
}
Question

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

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

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




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



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

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

1. upper
2. lower

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

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

희망 그 도움.




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



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

}



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



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




다음은 하나 개의 단순한 솔루션이다. 표시하고있는 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의로드의이 방법은 예입니다. 당신이 원하는대로 그것을 관리 할 수 ​​있습니다.




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

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




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

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



Links