如何在 UITableView Cell 中实现类似于 iOS 邮件的从左向右滑动

Posted

技术标签:

【中文标题】如何在 UITableView Cell 中实现类似于 iOS 邮件的从左向右滑动【英文标题】:How to Implement Swipe Left to Right in UITableView Cell similar to iOS Mail 【发布时间】:2014-11-16 08:46:48 【问题描述】:

我正在尝试复制 Apple 在其邮件应用程序中使用的相同技术,当您在邮箱内从左向右滑动时,将邮件标记为未读或“标记为未读”。

我找到了similarsolutions,但仅用于从右向左滑动的手势。我希望同样的解决方案可以作为 Apple SDK 的一部分用于相反的方向。

如何实现与 iOS 邮件应用相同的从左到右手势效果?

【问题讨论】:

我在我的应用程序中使用了这个库,效果很好:github.com/Dromaguirre/PDGestureTableView 有一个很棒的库MGSwipeTableCell。需要像ios Mail app那样实现滑动效果的大家,推荐使用。 【参考方案1】:

我找到了类似的解决方案,但只是从滑动手势 从右到左。

SWTableViewCell 拥有您可能需要的所有选项。

在对单元进行出队时,只需根据需要设置左/右按钮集。

cell.leftUtilityButtons = [self leftButtons];
cell.rightUtilityButtons = [self rightButtons];
cell.delegate = self;

通过将视图控制器设置为其委托,您可以监听按钮的点击。 有关如何实施的完整详细信息在该链接中

例 1:

例 2:

如果您正在寻找垂直堆叠的按钮,请查看this。

【讨论】:

@gh0st 如何在android中实现类似的效果?他们有图书馆吗? @gh0st 如何在Android中实现类似的效果?它看起来很酷。有图书馆什么的吗? 我不确定@NiteshKhatri,我还没有在 Android 上实现它。控制它的库是为 iOS 设备编写的。 有没有人尝试这个版本只是为了触摸单元格,然后单元格滑动? @Florjon 只需添加点击手势而不是滑动手势。【参考方案2】:

我通常在表级别实现它。

- (void)viewDidLoad

    [super viewDidLoad];

    UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                  action:@selector(leftSwipe:)];
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
    [self.tableView addGestureRecognizer:recognizer];

    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                        action:@selector(rightSwipe:)];
    recognizer.delegate = self;
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
    [self.tableView addGestureRecognizer:recognizer];

然后您可以控制方向并可以随意自定义

- (void)leftSwipe:(UISwipeGestureRecognizer *)gestureRecognizer

    //do you left swipe stuff here. 


- (void)rightSwipe:(UISwipeGestureRecognizer *)gestureRecognizer

    //do you right swipe stuff here. Something usually using theindexPath that you get that way
    CGPoint location = [gestureRecognizer locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];

归功于Jade Mind

【讨论】:

这个正确答案应该是没有在项目中实现第三方库的答案。由于苹果对接受应用程序非常严格,因此限制这种可能性是可以选择的。这一篇解释了开发者如何获取 leftToRight 滑动的gestureRecognizer。【参考方案3】:

从 iOS 11 开始,有原生规定(通过 UITableViewDelegate 委托方法)以在两侧的 UITableView 的单元格上启用“滑动操作”:

func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? //For actions at the left

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? //For actions at the right

这些方法返回一个包含UIContextualAction数组的UISwipeActionsConfiguration

对于UIContextualAction,您可以指定其标题、样式、背景颜色、动作颜色,甚至是UIImage 并处理其回调(显然:-))

这是一个示例实现:

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? 

    let filterAction = UIContextualAction(style: .normal, title: "FILTER")  (action, view, bool) in
        print("Swiped to filter")
    
    filterAction.backgroundColor = UIColor.blue

    return UISwipeActionsConfiguration(actions: [filterAction])

我知道这是一个老问题,但我发布这个只是为了以防它帮助随机路过的人......

【讨论】:

您可以在 func 之前添加“覆盖”,但这很好,谢谢 :) @Moitah 覆盖UITableViewDataSource 时需要覆盖,但如果你不这样做,则不需要override 这很奇怪,我继承 UITableViewController 和 Xcode 仍然是我需要 override 关键字。对我来说这似乎是合乎逻辑的,因为该方法来自 UITableViewDelegate ?谢谢【参考方案4】:

你可以在 Swift 5 中这样做:

func tableView(_ tableView: UITableView,
                leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?

    let closeAction = UIContextualAction(style: .normal, title:  "Close", handler:  (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
        print("OK, marked as Closed")
        success(true)
    )
    closeAction.image = UIImage(named: "tick")
    closeAction.backgroundColor = .purple
 
    return UISwipeActionsConfiguration(actions: [closeAction])

 
func tableView(_ tableView: UITableView,
                trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?

    let modifyAction = UIContextualAction(style: .normal, title:  "Update", handler:  (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
        print("Update action ...")
        success(true)
    )
    modifyAction.image = UIImage(named: "hammer")
    modifyAction.backgroundColor = .blue
 
    return UISwipeActionsConfiguration(actions: [modifyAction])

【讨论】:

【参考方案5】:

您提供的链接中接受的答案适用于两个滑动方向。 请注意,gestureRecognizer.directionUISwipeGestureRecognizerDirectionLeftUISwipeGestureRecognizerDirectionRight 返回 YES

您只需要修改几处: 更改在滑动时调用的选择器,因此它将调用您的方法,而不是帖子示例中的方法, 并将滑动方向更改为仅从左到右,而不是当前的两个方向,因为据我了解,您正在尝试设置单向滑动。

所以你的代码应该是这样的:

// In cellForRowAtIndexPath:, where you create your custom cell  
cell.tableView=tableView;  
cell.indexPath=indexPath;
UISwipeGestureRecognizer *swipeGestureRecognizer=[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(YOUR_METHOD_GOES_HERE)];
[cell addGestureRecognizer:swipeGestureRecognizer];  

-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch   
    if([[gestureRecognizer view] isKindOfClass:[UITableViewCell class]] && ((UISwipeGestureRecognizer*)gestureRecognizer.direction==UISwipeGestureRecognizerDirectionRight)  
        return YES;  

请注意,您也可以使用已接受答案下方的答案,只需将手势识别器direction 属性修改为UISwipeGestureRecognizerDirectionRight,而不是示例中的当前方向,即UISwipeGestureRecognizerDirectionLeft

如果您选择实现这一点,您的 viewController 必须实现手势识别器委托,您的代码应如下所示:

// Call this method in viewDidLoad  
- (void)setUpLeftSwipe   
    UISwipeGestureRecognizer *recognizer;  
    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                   action:@selector(swipeRightt:)];  
    [recognizer setDirection:UISwipeGestureRecognizerDirectionRight];  
    [self.tableView addGestureRecognizer:recognizer];  
    recognizer.delegate = self;  
  


- (void)swipeRight:(UISwipeGestureRecognizer *)gestureRecognizer   
    CGPoint location = [gestureRecognizer locationInView:self.tableView];  
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];  
    ... do something with cell now that i have the indexpath, maybe save the world? ...  
  

注意——如果我没记错的话,你需要自己创建单元格滑动动画,因为我相信 Xcode 的默认单元格动画只有在向左滑动时才会出现。

信用来自您提供的链接的MadhavanRPJulian。我刚刚修改了他们的答案以更好地满足您的需求。 不过,我自己还没有尝试并实现过。

【讨论】:

我真的希望得到一个更简单的答案,比如[buttonAction setAlignment:left] 或类似的东西。我想这并不容易。你认为这是 Apple 实现相同功能的方式吗? 我真的不知道。但是这段代码非常简单。虽然我自己没有测试过,但实现起来似乎并不复杂。试试吧,伙计,如果你需要帮助,尽管问。【参考方案6】:

将您的自定义 TableViewCell 与滚动视图一起使用,如下所示:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
   
    return 80;

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section

    return 120;


-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

    return header_view;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    return [array_field1 count];


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *CellIdentifier = @"Schedule_cell";

    Custom_Schedule_Cell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
        cell = (Custom_Schedule_Cell *)[Custom_Schedule_Cell cellFromNibNamed:@"Custom_Schedule_Cell"];
    

    x = 0;

        UILabel *lbl_title =[[UILabel alloc] initWithFrame:CGRectMake(x,0,cell.scroll_view.frame.size.width,cell.scroll_view.frame.size.height)];
        lbl_title.text=@"Title Array";
        [lbl_title setTextAlignment:NSTextAlignmentCenter];
        [lbl_title setFont:[UIFont fontWithName:@"Raleway" size:18.0f]];

        x += lbl_title.frame.size.width+10;

        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(x,0,110,cell.scroll_view.frame.size.height)];
        [button setTitle:@"Button1" forState:UIControlStateNormal];
        [button setBackgroundColor:[UIColor grayColor]];
        [button addTarget:self action:@selector(button1:) forControlEvents:UIControlEventTouchDown];
        button.tag = indexPath.row;
        [button.titleLabel setTextAlignment:NSTextAlignmentCenter];
        [button.titleLabel setFont:[UIFont fontWithName:@"Raleway" size:14.0f]];

    x += button.frame.size.width+5;

    UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(x,0,110,cell.scroll_view.frame.size.height)];
    [button2 setTitle:@"Button2" forState:UIControlStateNormal];
    [button2 setBackgroundColor:[UIColor grayColor]];
    [button2 addTarget:self action:@selector(button2:) forControlEvents:UIControlEventTouchDown];
    button2.tag = indexPath.row;
    [button2.titleLabel setTextAlignment:NSTextAlignmentCenter];
    [button2.titleLabel setFont:[UIFont fontWithName:@"Raleway" size:14.0f]];

    x += button2.frame.size.width+5;


    UIButton *button3 = [[UIButton alloc] initWithFrame:CGRectMake(x,0,110,cell.scroll_view.frame.size.height)];
    [button3 setTitle:@"Button3" forState:UIControlStateNormal];
    [button3 setBackgroundColor:[UIColor grayColor]];
    [button3 addTarget:self action:@selector(button3:) forControlEvents:UIControlEventTouchDown];
    button3.tag = indexPath.row;
    [button3.titleLabel setTextAlignment:NSTextAlignmentCenter];
    [button3.titleLabel setFont:[UIFont fontWithName:@"Raleway" size:14.0f]];

        [cell.scroll_view addSubview:lbl_title];
        [cell.scroll_view addSubview:button];
    [cell.scroll_view addSubview:button2];
    [cell.scroll_view addSubview:button3];

    x += button3.frame.size.width+5;

    cell.scroll_view.contentSize = CGSizeMake(x,cell.scroll_view.frame.size.height);
    cell.scroll_view.showsHorizontalScrollIndicator = NO;
    cell.scroll_view.showsVerticalScrollIndicator = NO;
    [cell.scroll_view setContentOffset:CGPointMake(0,0) animated:NO];
    [cell.scroll_view setPagingEnabled:true];
    return cell;


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

//    Custom_Schedule_Cell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
//    [selectedCell.scroll_view setContentOffset:CGPointMake(x2,0) animated:NO];


-(void)button1:(UIButton *)button

    NSLog(@“button1 Click ");
    [button setBackgroundColor:[UIColor redColor]];


-(void)button2:(UIButton *)button

    NSLog(@“button2 Click");
    [button setBackgroundColor:[UIColor greenColor]];


-(void)button3:(UIButton *)button

    NSLog(@“button Click");
    [button setBackgroundColor:[UIColor redColor]];

【讨论】:

以上是关于如何在 UITableView Cell 中实现类似于 iOS 邮件的从左向右滑动的主要内容,如果未能解决你的问题,请参考以下文章

如何在派生类中实现类的基本函数

在 pyspark 中实现类不平衡算法

在python中实现类接口的正确方法是啥

在 Scala Slick 中实现类实例成员修改的最佳方法?

即使在 XCTest 文件中实现类扩展中的方法后,仍会调用协议的默认实现

UITableView优化