iOS 7:UITableViewController:更改/替换删除按钮

4

免责声明:我知道调整这种东西不是最佳实践,因为苹果可能会更改其内部行为而导致出错。

有一些解决方案在网上流传,例如https://dev59.com/vnI-5IYBdhLWcg3w6dC2#12511432在先前的iOS版本中似乎可以工作,但对于iOS 7则不行。

当查看控件层次结构时,我可以看到UITableViewCellScrollView中有一个UITableViewCellDeleteConfirmationView。但是,在layoutSubviews或willTransitionToState中查看子视图集合时,只有我的视图,UITableViewCellDeleteConfirmationView不会出现。

enter image description here

所以,有人找到了如何修改默认的删除按钮/视图吗?


可能是重复问题:https://dev59.com/DmQm5IYBdhLWcg3w4CXA - Krumelur
不是的。而且答案也没有被正确回答。 - asp_net
“如何调整不应该调整的UI层次结构”没有正确答案 - 它总是一个hack。第二和第三个答案似乎是一个有效的方法。 - Krumelur
问题实际上是:你想要一个删除按钮吗?那么保留默认行为。你想要其他的东西吗?那么实现自己的UITableViewCell并添加手势识别器来隐藏/显示你自己的按钮。 - Krumelur
我在我的应用程序中使用红色的tintColor,它与删除按钮背景颜色使用的橙红色产生了严重的冲突,将其设置为与我的tintColor相同的UIColor将非常理想,我认为为此添加自己的手势识别器有点过度。如果我们可以直接修改这样的边缘情况,那就太好了,这是一个很好的问题。 - Billy Gray
3个回答

4

我知道你可能不想覆盖苹果为编辑表视图单元格而实现的整个方案,但我有一个类似的问题。在我的应用中,当用户向左滑动时,我需要两个按钮(More和Lost)像iOS7新提醒应用程序中一样显示。与其使用:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

我创建了一个自定义单元格,它将按钮隐藏在顶部层下,并使用拖动手势识别器移动顶部层,显示底部的按钮。因此,我完全控制显示哪些按钮,以及它们的颜色等(见下文)。
static CGFloat const kEditButtonWidth = 82.0;

@interface MyCustomCell ()
@property (nonatomic, assign) CGFloat firstX;
@property (nonatomic, assign) CGFloat firstY;
@property (nonatomic, strong) UIView *topLayer;
@property (nonatomic, strong) UIButton *moreButton;
@property (nonatomic, strong) UIButton *lostButton;
@property (nonatomic, strong) UILabel *titleLabel;
@end

@implementation MyCustomCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self) {

        // BOTTOM LAYER (MORE AND LOST BUTTONS)
        UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [aButton setFrame:CGRectZero];
        [aButton setTitle:@"More" forState:UIControlStateNormal];
        [aButton setTitleShadowColor:[UIColor clearColor] forState:UIControlStateNormal];
        [aButton setBackgroundColor:[UIColor colorWithRed:0.78 green:0.78 blue:0.78 alpha:1.0]];
        [[self contentView] addSubview:aButton];
        [self setMoreButton:aButton];

        aButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [aButton setFrame:CGRectZero];
        [aButton setTitle:@"Lost" forState:UIControlStateNormal];
        [aButton setTitleShadowColor:[UIColor clearColor] forState:UIControlStateNormal];
        [aButton setBackgroundColor:[UIColor colorWithRed:1.00f green:0.23f blue:0.19f alpha:1.00f]];
        [[self contentView] addSubview:aButton];
        [self setLostButton:aButton];

        // TOP LAYER
        UIView *aView = [[UIView alloc] initWithFrame:CGRectZero];
        [aView setBackgroundColor:[UIColor whiteColor]];
        [[self contentView] addSubview:aView];
        [self setTopLayer:aView];

        UIPanGestureRecognizer *aPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAction:)];
        [aPanRecognizer setMinimumNumberOfTouches:1];
        [aPanRecognizer setMaximumNumberOfTouches:1];
        [aView addGestureRecognizer:aPanRecognizer];

        // title label
        UILabel *aLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        [aView addSubview:aLabel];
        [self setTitleLabel:aLabel];
    }
    return self;
}

- (void)layoutSubviews {

    [super layoutSubviews];

    CGRect bounds = [[self contentView] bounds];
    CGRect frame = CGRectZero;

    // BOTTOM LAYER (MORE AND LOST BUTTONS)
    frame.origin.x = bounds.size.width-(kEditButtonWidth+kEditButtonWidth); // two buttons wide
    frame.size.width = kEditButtonWidth;
    frame.size.height = bounds.size.height;
    [[self moreButton] setFrame:frame];

    frame.origin.x += kEditButtonWidth;
    [[self lostButton] setFrame:frame];

    // TOP LAYER
    frame = bounds;
    CGPoint anchorPoint = CGPointMake(0.0f, [[[self topLayer] layer] anchorPoint].y);
    [[[self topLayer] layer] setAnchorPoint:anchorPoint];
    [[self topLayer] setFrame:frame];

    // title label
    frame.origin.x = 20.0;
    frame.origin.y = 4.0;
    frame.size.width = bounds.size.width-40.0;
    frame.size.height = 21.0;
    [[self titleLabel] setFrame:frame];
}

- (void)panGestureAction:(id)sender {

    // on the first touch, get the center coordinates (x and y) of the view
    CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self];
    if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
        [self setFirstX:[[sender view] center].x];
        [self setFirstY:[[sender view] center].y];
    }

    // add translated point to reference points
    translatedPoint = CGPointMake([self firstX]+translatedPoint.x, [self firstY]);
    [[sender view] setCenter:translatedPoint];

    // when pan ends (set final x to be either back to zero or showing buttons)
    if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
        CGFloat finalX = translatedPoint.x+(0.30*[(UIPanGestureRecognizer*)sender velocityInView:self].x);
        if (finalX < -1.0f*FMEditButtonWidth) {
            finalX = -2.0f*FMEditButtonWidth;
            [self setEditMode:YES];
        } else {
            finalX = 0.0f;
            [self setEditMode:NO];
        }

        // animate view
        [UIView animateWithDuration:1.0 delay:0.0 usingSpringWithDamping:1.0f initialSpringVelocity:1.0f options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState animations:^{
            [[sender view] setCenter:CGPointMake(finalX, [self firstY])];
        } completion:NULL];
    }
}

@end

希望这能有所帮助。

谢谢分享!我会在接下来的几周内尝试一下。 - asp_net
我尝试了这个代码,但是我无法弄清为什么手势没有被识别。方法没有被调用。你能帮我吗? - alexdd55
@alexdd55 在 initWithStyle: 中设置一个断点,以查看它是否触发并正确连接您的手势。 - Billy Gray
你如何检测何时隐藏更多和丢失的按钮?我无法弄清楚如何使其一次只能滑动一个单元格。 - AlBeebe

0
你看不到在 layoutSubviews 或者 willTransitionToState: 中的视图,是因为删除按钮视图还不存在,或者它还没有成为视图层次结构的一部分。 为了“看到”它,需要稍微延迟浏览视图层次结构的代码,这样允许操作系统在此期间创建/添加视图:

- (void)willTransitionToState:(UITableViewCellStateMask)state
{
    [super willTransitionToState:state];

    if (state & UITableViewCellStateShowingDeleteConfirmationMask)
    {
        [self performSelector:@selector(findDeleteButtonViewThroughViewHierarchy:) withObject:self.subviews afterDelay:0];
    }
}

请注意,这是一种脆弱的解决方案,因为它基于苹果的内部实现,随时可能发生变化。
以下是一个(几乎)完整的示例:

自定义iOS 7删除按钮


-1

不确定这是否适用于iOS 7,但看一下:

(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{

  if (editingStyle == UITableViewCellEditingStyleDelete)

   {

    //   Your Code

    }
}

这个方法在点击按钮时被调用,所以有点晚了 - 但还是谢谢;-)。 - asp_net

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接