简体   繁体   English

如何更改 UITableViewRowAction 标题颜色?

[英]How to change UITableViewRowAction title color?

Am using UITableViewRowAction in "editActionsForRowAtIndexPath" method.在“editActionsForRowAtIndexPath”方法中使用 UITableViewRowAction。 I can change the backgroundcolor of UITableViewRowAction, but am not able to change the title color.我可以更改 UITableViewRowAction 的背景颜色,但无法更改标题颜色。 But I would like to change the color of the UITableViewRowAction.但我想更改 UITableViewRowAction 的颜色。 Any inputs on this regard will be appreciable.在这方面的任何投入都将是可观的。

There is one way that can achieve what you are looking for.有一种方法可以实现您的目标。 But it is little tricky though.但这有点棘手。

Example of result:结果示例:

在此处输入图片说明

The idea of this trick is that you can actually modify background color.这个技巧的想法是你实际上可以修改背景颜色。 This means that you can set UIColor's +colorWithPatternImage: and set an bitmap image that match desired styling.这意味着您可以设置 UIColor 的 +colorWithPatternImage: 并设置匹配所需样式的位图图像。 This can be achieved either by creating image using graphic editor or by rendering it using for example Core Graphics.这可以通过使用图形编辑器创建图像或使用例如 Core Graphics 渲染它来实现。 The only problem with this solution is, that you have to mimic original title length with you specific text attributes to make it work properly and also you must set title for table view row action as string of white spaces so that table view cell will prepare enough space for you "custom action button".此解决方案的唯一问题是,您必须使用特定文本属性模仿原始标题长度以使其正常工作,并且您必须将表格视图行操作的标题设置为空格字符串,以便表格视图单元格准备足够为您提供“自定义操作按钮”的空间。 Creating static png assets in photoshop may be inappropriate if you use variable cell rows.如果您使用可变单元格行,在 photoshop 中创建静态 png 资产可能不合适。

This is category for NSString that creates string of empty spaces that will create space for your custom button and second will generate bitmap image that will be placed as background pattern image.这是 NSString 的类别,它创建一串空格,为您的自定义按钮创建空间,第二个将生成位图图像,该图像将放置为背景图案图像。 For parameters you must set text attributes for original title, that is basically @{NSFontAttributeName: [UIFont systemFontOfSize:18]} , than your desired text attributes.对于参数,您必须为原始标题设置文本属性,基本上是@{NSFontAttributeName: [UIFont systemFontOfSize:18]} ,而不是您想要的文本属性。 Maybe there is better way to achieve this :)也许有更好的方法来实现这一点:)

@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

Second important part is code that renders bitmap that can be used as pattern image for UITableViewRowAction's backgroundColor.第二个重要部分是呈现位图的代码,该位图可用作 UITableViewRowAction 的 backgroundColor 的图案图像。

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

And then when you are creating your row action you can do something like this:然后当您创建行操作时,您可以执行以下操作:

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

This solution is obviously hacky but you can achieve desired results without using private APIs and in future if something breaks, this will not break your app.这个解决方案显然是 hacky 但是你可以在不使用私有 API 的情况下达到预期的结果,将来如果出现问题,这不会破坏你的应用程序。 Only button will look inappropriate.只有按钮看起来不合适。

Example of result:结果示例:

在此处输入图片说明

This code has of course a lot of space for improvements, any suggestions are appreciated.这段代码当然有很大的改进空间,任何建议都表示赞赏。

I'm afraid that there's no way to change the title color of the UITableViewRowAction.恐怕没有办法改变 UITableViewRowAction 的标题颜色。

The only things you can change on the action are:您可以在操作中更改的唯一内容是:

  • backgroundColor背景颜色
  • style (destructive (red backgroundcolor, ...)风格(破坏性(红色背景色,...)
  • title标题

For more info, please refer to the Apple Doc UITableViewRowAction有关更多信息,请参阅Apple Doc UITableViewRowAction

Swift迅速

No need to mess with UIButton.appearance...无需弄乱 UIButton.appearance...

Put this in your cell's class and change UITableViewCellActionButton according to your needs.把它放在你单元格的类中,并根据你的需要更改 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
                        }

                    }
                }
            }
        }
    }

}

There is indeed a way to change the title color of the UITableViewRowAction.确实有一种方法可以更改 UITableViewRowAction 的标题颜色。 It's a button.这是一个按钮。 You can use the UIButton appearance proxy:您可以使用UIButton外观代理:

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

在此处输入图片说明

Lee Andrew's answer in Swift 3 / Swift 4 : 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

                            }

                        }

                    }

                }

            }

        }

    }

}

So there still is no public api to change textColor or font to the cells action in the iOS 13 days.因此, iOS 13天中仍然没有公共 api 可以将textColorfont更改为单元格操作。

Working solution for Swift 5.3, iOS 14适用于 Swift 5.3、iOS 14 的工作解决方案

Hacks from answers in the thread have very unreliable results but I have managed to get my version of the hack working.来自线程中答案的黑客具有非常不可靠的结果,但我已经设法让我的黑客版本正常工作。

1. Getting the label 1. 获取标签

Here is my simplified way of accessing the actions UILabel :这是我访问操作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. Updating the label on layout changes 2. 更新布局变化的标签

Next, overriding layoutSubviews() in my UITableViewCell subclass wasn't enough so additionally I had to override layoutIfNeeded() for the hack to work.接下来,在我的UITableViewCell子类中覆盖layoutSubviews()是不够的,所以另外我必须覆盖layoutIfNeeded()才能使 hack 工作。 Note that it's important to override both of them!请注意,覆盖它们很重要

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. Triggering extra layout refresh 3.触发额外的布局刷新

The last piece of the puzzle is to schedule an additional refresh of the color, so we cover all of those cases where for some reason above functions would not get called.难题的最后一部分是安排额外的颜色刷新,因此我们涵盖了由于某种原因上述函数不会被调用的所有情况。 The best place for doing so is UITableViewDelegate method ..., willBeginEditingRowAt: ...这样做的最佳位置是UITableViewDelegate方法..., willBeginEditingRowAt: ...

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

A delayed layout refresh trigger does the trick of letting the UIKit configure the cell first, so we can jump right after with the customisation.延迟布局刷新触发器的作用是让 UIKit 首先配置单元格,因此我们可以在自定义之后立即跳转。 0.01 was just enough for me but i can probably vary from case to case. 0.01对我来说已经足够了,但我可能会因情况而异。

4. Profit 4. 利润

Now you can customise the label anyway you want!现在您可以随意自定义标签! Change the text, its color, font or add a subview!更改文本、颜色、字体或添加子视图!

It goes without saying that this can break -anytime- if Apple will decide to change their private implementation.不言而喻,如果 Apple 决定改变他们的私有实现,这可能会随时中断。

iOS 11 solution: iOS 11解决方案:

Create UITableViewCell extension like this:像这样创建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
    }

}

And write this in your UITableViewCell并将其写入您的UITableViewCell

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

But there is a bug - if you pull the cell fast this code sometimes doesn't change the color.但是有一个错误——如果你快速拉动单元格,这段代码有时不会改变颜色。

You can add these two functions in your UITableViewCell subclass and call the setActionButtonsTitleColor function to set action buttons' title color.您可以在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
}
-(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];

IF someone is still looking for an alternative solution:如果有人仍在寻找替代解决方案:

You can use the swipecellkit pod您可以使用 swipecellkit pod

https://github.com/SwipeCellKit/SwipeCellKit https://github.com/SwipeCellKit/SwipeCellKit

This lets you customize the label color, image color and even the entire background while perserving the actual look and feel of the native implementation.这使您可以自定义标签颜色、图像颜色甚至整个背景,同时保持本机实现的实际外观和感觉。

Thanks @Witek for sharing.感谢@Witek 的分享。

Your solution works but it's not stable.您的解决方案有效,但不稳定。 So, I try to update your code, and now it's working very well.所以,我尝试更新您的代码,现在它运行良好。

Put this code below in your UITableViewCell将此代码放在您的 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM