How to change UITableViewRowAction title color?

后端 未结 10 858
梦如初夏
梦如初夏 2020-11-30 05:49

Am using UITableViewRowAction in \"editActionsForRowAtIndexPath\" method. I can change the backgroundcolor of UITableViewRowAction, but am not able to change the title color

相关标签:
10条回答
  • 2020-11-30 06:21

    There is indeed a way to change the title color of the UITableViewRowAction. It's a button. You can use the UIButton appearance proxy:

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

    enter image description here

    0 讨论(0)
  • 2020-11-30 06:21

    So there still is no public api to change textColor or font to the cells action in the iOS 13 days.

    Working solution for 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

    Here is my simplified way of accessing the actions 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

    Next, overriding layoutSubviews() in my UITableViewCell subclass wasn't enough so additionally I had to override layoutIfNeeded() for the hack to work. 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

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

    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. 0.01 was just enough for me but i can probably vary from case to case.

    4. Profit

    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.

    0 讨论(0)
  • 2020-11-30 06:26

    There is one way that can achieve what you are looking for. But it is little tricky though.

    Example of result:

    enter image description here

    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. This can be achieved either by creating image using graphic editor or by rendering it using for example 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.

    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. For parameters you must set text attributes for original title, that is basically @{NSFontAttributeName: [UIFont systemFontOfSize:18]}, than your desired text attributes. 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.

    - (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. Only button will look inappropriate.

    Example of result:

    enter image description here

    This code has of course a lot of space for improvements, any suggestions are appreciated.

    0 讨论(0)
  • 2020-11-30 06:30

    iOS 11 solution:

    Create UITableViewCell extension like this:

    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

    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.

    0 讨论(0)
  • 2020-11-30 06:31

    I'm afraid that there's no way to change the title color of the 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

    0 讨论(0)
  • 2020-11-30 06:32

    IF someone is still looking for an alternative solution:

    You can use the swipecellkit pod

    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.

    0 讨论(0)
提交回复
热议问题