22

我在“editActionsForRowAtIndexPath”方法中使用 UITableViewRowAction。我可以更改 UITableViewRowAction 的背景颜色,但无法更改标题颜色。但我想更改 UITableViewRowAction 的颜色。在这方面的任何投入都将是可观的。

4

11 回答 11

19

有一种方法可以实现您正在寻找的东西。但这有点棘手。

结果示例:

在此处输入图像描述

这个技巧的想法是你实际上可以修改背景颜色。这意味着您可以设置 UIColor 的 +colorWithPatternImage: 并设置与所需样式匹配的位图图像。这可以通过使用图形编辑器创建图像或使用例如 Core Graphics 渲染它来实现。此解决方案的唯一问题是,您必须使用特定的文本属性来模拟原始标题长度以使其正常工作,并且您必须将表格视图行操作的标题设置为空格字符串,以便表格视图单元格准备足够为您提供“自定义操作按钮”的空间。如果您使用可变单元格行,则在 Photoshop 中创建静态 png 资源可能不合适。

这是 NSString 的类别,它创建一串空白空间,为您的自定义按钮创建空间,第二个将生成将作为背景图案图像放置的位图图像。对于参数,您必须为原始标题设置文本属性,基本上就是@{NSFontAttributeName: [UIFont systemFontOfSize:18]}您想要的文本属性。也许有更好的方法来实现这一点:)

@implementation NSString (WhiteSpace)

- (NSString *)whitespaceReplacementWithSystemAttributes:(NSDictionary *)systemAttributes newAttributes:(NSDictionary *)newAttributes
{
    NSString *stringTitle = self;
    NSMutableString *stringTitleWS = [[NSMutableString alloc] initWithString:@""];

    CGFloat diff = 0;
    CGSize  stringTitleSize = [stringTitle sizeWithAttributes:newAttributes];
    CGSize stringTitleWSSize;
    NSDictionary *originalAttributes = systemAttributes;
    do {
        [stringTitleWS appendString:@" "];
        stringTitleWSSize = [stringTitleWS sizeWithAttributes:originalAttributes];
        diff = (stringTitleSize.width - stringTitleWSSize.width);
        if (diff <= 1.5) {
            break;
        }
    }
    while (diff > 0);

    return [stringTitleWS copy];
}

@end

第二个重要部分是渲染位图的代码,该位图可用作 UITableViewRowAction 的背景颜色的图案图像。

- (UIImage *)imageForTableViewRowActionWithTitle:(NSString *)title textAttributes:(NSDictionary *)attributes backgroundColor:(UIColor *)color cellHeight:(CGFloat)cellHeight
{
    NSString *titleString = title;
    NSDictionary *originalAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:18]};
    CGSize originalSize = [titleString sizeWithAttributes:originalAttributes];
    CGSize newSize = CGSizeMake(originalSize.width + kSystemTextPadding + kSystemTextPadding, originalSize.height);
    CGRect drawingRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, cellHeight));
    UIGraphicsBeginImageContextWithOptions(drawingRect.size, YES, [UIScreen mainScreen].nativeScale);
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(contextRef, color.CGColor);
    CGContextFillRect(contextRef, drawingRect);

    UILabel *label = [[UILabel alloc] initWithFrame:drawingRect];
    label.textAlignment = NSTextAlignmentCenter;
    label.attributedText = [[NSAttributedString alloc] initWithString:title attributes:attributes];
    [label drawTextInRect:drawingRect];

    //This is other way how to render string 
    //    CGSize size = [titleString sizeWithAttributes:attributes];
    //    CGFloat x =  (drawingRect.size.width - size.width)/2;
    //    CGFloat y =  (drawingRect.size.height - size.height)/2;
    //    drawingRect.origin = CGPointMake(x, y);
    //    [titleString drawInRect:drawingRect withAttributes:attributes];

    UIImage *returningImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return returningImage;
}

然后,当您创建行操作时,您可以执行以下操作:

NSDictionary *systemAttributes = @{ NSFontAttributeName: [UIFont systemFontOfSize:18] };
NSDictionary *newAttributes = @{NSFontAttributeName: [UIFont fontWithName:@"Any font" size:15]};
NSString *actionTitle = @"Delete";
NSString *titleWhiteSpaced = [actionTitle whitespaceReplacementWithSystemAttributes:systemTextFontAttributes newAttributes:newAttributes];
UITableViewRowAction *rowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:titleWhiteSpaced handle:NULL];
UIImage *patternImage = [self imageForTableViewRowActionWithTitle:actionTitle textAttributes:newAttributes backgroundColor:[UIColor redColor] cellHeight:50];
rowAction.backgroundColor = [UIColor colorWithPatternImage:patternImage]; 

这个解决方案显然是 hacky,但是您可以在不使用私有 API 的情况下获得所需的结果,并且将来如果出现问题,这不会破坏您的应用程序。只有按钮看起来不合适。

结果示例:

在此处输入图像描述

这段代码当然有很大的改进空间,欢迎提出任何建议。

于 2014-11-28T00:51:15.060 回答
13

恐怕没有办法改变 UITableViewRowAction 的标题颜色。

您可以更改的唯一操作是:

  • 背景颜色
  • 风格(破坏性(红色背景色,...)
  • 标题

有关更多信息,请参阅Apple 文档 UITableViewRowAction

于 2014-11-12T13:20:48.693 回答
9

迅速

无需弄乱 UIButton.appearance...

把它放在你的单元格的类中,并根据你的需要更改 UITableViewCellActionButton 。

override func layoutSubviews() {

    super.layoutSubviews()

    for subview in self.subviews {

        for subview2 in subview.subviews {

            if (String(subview2).rangeOfString("UITableViewCellActionButton") != nil) {

                for view in subview2.subviews {

                    if (String(view).rangeOfString("UIButtonLabel") != nil) {

                        if let label = view as? UILabel {

                            label.textColor = YOUR COLOUR
                        }

                    }
                }
            }
        }
    }

}
于 2016-03-22T03:40:01.123 回答
5

确实有办法改变 UITableViewRowAction 的标题颜色。这是一个按钮。您可以使用UIButton外观代理:

[[UIButton appearance] setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];

在此处输入图像描述

于 2014-12-10T18:50:19.847 回答
5

Lee AndrewSwift 3 / Swift 4中的回答:

class MyCell: UITableViewCell {

    override func layoutSubviews() {
        super.layoutSubviews()

        for subview in self.subviews {

            for sub in subview.subviews {

                if String(describing: sub).range(of: "UITableViewCellActionButton") != nil {

                    for view in sub.subviews {

                        if String(describing: view).range(of: "UIButtonLabel") != nil {

                            if let label = view as? UILabel {

                                label.textColor = UIColor.black

                            }

                        }

                    }

                }

            }

        }

    }

}
于 2017-04-22T20:21:52.387 回答
4

所以在iOS 13天仍然没有公共 api 可以更改textColorfont单元格操作。

适用于 Swift 5.3、iOS 14 的工作解决方案

来自线程中答案的黑客具有非常不可靠的结果,但我已经设法让我的黑客版本正常工作。

1. 获取标签

这是我访问操作的简化方式UILabel

extension UITableViewCell {
    var cellActionButtonLabel: UILabel? {
        superview?.subviews
            .filter { String(describing: $0).range(of: "UISwipeActionPullView") != nil }
            .flatMap { $0.subviews }
            .filter { String(describing: $0).range(of: "UISwipeActionStandardButton") != nil }
            .flatMap { $0.subviews }
            .compactMap { $0 as? UILabel }.first
    }
}

2. 更新布局更改的标签

接下来,layoutSubviews()在我的UITableViewCell子类中重写是不够的,所以我还必须重写layoutIfNeeded()才能使黑客工作。请注意,覆盖它们很重要!

override func layoutSubviews() {
    super.layoutSubviews()
    cellActionButtonLabel?.textColor = .black // you color goes here
}
override func layoutIfNeeded() {
    super.layoutIfNeeded()
    cellActionButtonLabel?.textColor = .black // you color goes here
}

3.触发额外的布局刷新

难题的最后一部分是安排额外的颜色刷新,因此我们涵盖了由于某种原因上述函数不会被调用的所有情况。这样做最好的地方是UITableViewDelegate方法..., willBeginEditingRowAt: ...

func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
        tableView.cellForRow(at: indexPath)?.layoutIfNeeded()
    }
}

延迟布局刷新触发器可以让 UIKit 首先配置单元格,因此我们可以在自定义之后立即跳转。0.01对我来说已经足够了,但我可能会因情况而异。

4. 利润

现在您可以随心所欲地自定义标签!更改文本、颜色、字体或添加子视图!

不用说,如果 Apple 决定改变他们的私有实现,这可能随时中断。

于 2020-05-19T18:13:23.410 回答
3

iOS 11解决方案:

像这样创建UITableViewCell扩展:

extension UITableViewCell {

    /// Returns label of cell action button.
    ///
    /// Use this property to set cell action button label color.
    var cellActionButtonLabel: UILabel? {
        for subview in self.superview?.subviews ?? [] {
            if String(describing: subview).range(of: "UISwipeActionPullView") != nil {
                for view in subview.subviews {
                    if String(describing: view).range(of: "UISwipeActionStandardButton") != nil {
                        for sub in view.subviews {
                            if let label = sub as? UILabel {
                                return label
                            }
                        }
                    }
                }
            }
        }
        return nil
    }

}

并写在你的UITableViewCell

override func layoutSubviews() {
    super.layoutSubviews()
    cellActionButtonLabel?.textColor = .red
}

但是有一个错误——如果你快速拉单元格,这个代码有时不会改变颜色。

于 2018-04-09T15:49:44.180 回答
1

您可以在UITableViewCell子类中添加这两个函数并调用该setActionButtonsTitleColor函数来设置操作按钮的标题颜色。

func setActionButtonsTitleColor(color: UIColor) {
  let actionButtons: [UIButton] = self.getActionButtons()

  for actionButton in actionButtons {
    actionButton.setTitleColor(color, for: .normal)
  }
}

func getActionButtons() -> [UIButton] {
  let actionButtons: [UIButton] = self.subviews.map {
    (view: UIView) -> [UIView] in
    return view.subviews
  }
  .joined()
  .filter {
    (view: UIView) -> Bool in
    return String(describing: view).contains("UITableViewCellActionButton")
  }.flatMap {
    (view: UIView) -> UIButton? in
    return view as? UIButton
  }

  return actionButtons
}
于 2017-06-08T07:54:18.537 回答
0
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewRowAction *editAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"edit" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
    {
    // Action something here

}];

editAction.backgroundColor = [UIColor whiteColor];
[[UIButton appearance] setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

return @[editAction];
于 2017-01-10T15:29:49.753 回答
0

如果有人仍在寻找替代解决方案:

您可以使用 swipecellkit 吊舱

https://github.com/SwipeCellKit/SwipeCellKit

这使您可以自定义标签颜色、图像颜色甚至整个背景,同时保持本机实现的实际外观。

于 2018-11-22T14:56:33.597 回答
0

感谢@Witek 的分享。

您的解决方案有效,但不稳定。因此,我尝试更新您的代码,现在它运行良好。

将此代码放在您的 UITableViewCell 中

override func layoutSubviews() {
    super.layoutSubviews()
    if let button = actionButton {
        button.setTitleColor(.black, for: .normal)
    }
}

override func layoutIfNeeded() {
    super.layoutIfNeeded()
    if let button = actionButton {
        button.setTitleColor(.black, for: .normal)
    }
}

var actionButton: UIButton? {
    superview?.subviews
        .filter({ String(describing: $0).range(of: "UISwipeActionPullView") != nil })
        .flatMap({ $0.subviews })
        .filter({ String(describing: $0).range(of: "UISwipeActionStandardButton") != nil })
        .compactMap { $0 as? UIButton }.first
}
于 2021-10-22T05:17:17.873 回答