How to do custom font and color in UITableViewRowAction without Storyboard
Asked Answered
S

9

11

I have classic TableView where you can delete item if you swipe and than clicking on the button. I know how to set custom background on the cell, but I can't find how I can set custom font and color for that.

Thank you for help!

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]?  {

    var deleteAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, 
                   title: "Delete", 
                   handler: { 
                      (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
                           println("Delete button clicked!")
                   })

    deleteAction.backgroundColor = UIColor.redColor()

    return [deleteAction]
}
Skeie answered 14/3, 2015 at 13:11 Comment(1)
Check my answer on this post: https://mcmap.net/q/23776/-how-to-change-uitableviewrowaction-title-colorEdmund
D
-18

How to use a custom font?

It's pretty easy.

  1. Firstly, you need to include your custom font files to your project.
  2. Next, go to your info.plist file and add a new entry with the key "Fonts provided by application". Note that this entry should be an Array.
  3. Then add the names of these files as elements of this array.

And that's it! All you need then is to use the font by its name like this

cell.textLabel.font = [UIFont fontWithName:@"FontName" size:16];

How to change the font color?

Even easier. All you need is

cell.textlabel.textcolor = UIColor.redColor()

Edit:

In your case you want to change the font of the RowAction. So I think of only 2 solutions. One to use [UIColor colorWithPatterImage:]

Or you can user [[UIButton appearance] setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; because the RowAction contains a button.

Dorsett answered 14/3, 2015 at 15:39 Comment(14)
Thank you, but this is not the right answer what I need. You help me implement custom font, that I know. I need set color/font for the cell in UITableViewActionRow. (the pink here: https://www.dropbox.com/s/jaineb3qgcezm90/Screenshot%202015-03-15%2009.14.51.png?dl=0) The code what you wrote me not working, because in the action what you can see in my first post here, you can work just with "title" but the title is reserved for localization only. Any idea how to fix it?Skeie
OMG! You made my day buddy! Thanks. I just rewrote your code to the Swift version and all working perfectly. UIButton.appearance().setTitleColor(UIColor.orangeColor(), forState: UIControlState.Normal) EDIT: And do you know, how I set the custom font for the button? I can't find function like "setTitleFont" there.Skeie
I guess something like the following: NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:@"YOURFONT" size:14], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, nil]; [[UIButton appearance] setTitleTextAttributes:attributes];Dorsett
Do you know the code in Swift? I can't do that without errors. :/Skeie
I guess it would be something like this ` let attributes: Dictionary = [NSFontAttributeName: UIFont(name: "HelveticaNeue-Light", size: 19)!] UIButton.appearance().setValuesForKeysWithDictionary(attributes)`Dorsett
The app crash, if I paste the code. And one more thing here: this scope is for all buttons in the app. Can I specified it just for the "Delete" button?Skeie
Sadly, I can get a hand on the reference. We are making a workaround. Try this line UIButton.appearance().setValueForKeyPath and your keyPath is Button.fontDorsett
I can't use setValueForKeyPath on the button, it works for you?.... I'm trying something like this UIButton.appearance().titleLabel?.font = UIFont(name: "Futura", size: 40) but still not working, is it without error, but the size and font is still on default.Skeie
Hey buddy, any idea there? :)) Thanks a lot!Skeie
Hey, pal! Sorry was a heavy day for me. Will dig that for you. :)Dorsett
I have found a solution that you may not like. You can adjust the appearance of UILabel as well to include the font.Dorsett
I'm not understand what you mean now. Can you show me? I want just change the font, with easy way like the font color.Skeie
Try this one UILabel.appearance().font = UIFont(name: "", size: 17)Dorsett
Yep, that is not optimal solution, but still not working. I'm just trying it right now and doesn't work. :(Skeie
J
11

Well, the only way I've found to set a custom font is to use the appearanceWhenContainedIn method of the UIAppearance protocol. This method isn't yet available in Swift, so you have to do it in Objective-C.

I made a class method in a utility Objective-C class to set it up:

+ (void)setUpDeleteRowActionStyleForUserCell {

    UIFont *font = [UIFont fontWithName:@"AvenirNext-Regular" size:19];

    NSDictionary *attributes = @{NSFontAttributeName: font,
                      NSForegroundColorAttributeName: [UIColor whiteColor]};

    NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString: @"DELETE"
                                                                          attributes: attributes];

    /*
     * We include UIView in the containment hierarchy because there is another button in UserCell that is a direct descendant of UserCell that we don't want this to affect.
     */
    [[UIButton appearanceWhenContainedIn:[UIView class], [UserCell class], nil] setAttributedTitle: attributedTitle
                                                                                          forState: UIControlStateNormal];
}

This works, but it's definitely not ideal. If you don't include UIView in the containment hierarchy, then it ends up affecting the disclosure indicator as well (I didn't even realize the disclosure indicator was a UIButton subclass). Also, if you have a UIButton in your cell that is inside a subview in the cell, then that button will get affected by this solution as well.

Considering the complications, it might be better to just use one of the more customizable open source libraries out there for table cell swipe options.

Jonniejonny answered 21/4, 2015 at 16:21 Comment(6)
I have figured out an improvement on this answer to avoid affecting other buttons inside the cell. After inspecting the view hierarchy of an expanded cell, I found that the delete button is sitting inside a UITableViewCellDeleteConfirmationView view. This is a private API but using this instead of UIView targets only the delete button and not any other button in the cell. So instead of [UIView class], use [NSClassFromString(@"UITableViewCellDeleteConfirmationView") class]Minx
@Minx Can you confirm if your app passed the review, or they rejected it because you used the private API?Regulation
This was a while ago and my app has passed several reviews without a problem.Minx
How to add more buttons in this way?Tinware
After doing a grep following this nshipster.com/uiappearance, doesn't seem that setAttributedTitle:forState: is available for UIButton customization. Can you confirm that this answer still works?Customhouse
does not work for me, at least on iOS 12. The button is contained in a private class view called UISwipeActionPullView so you have to use NSClassFromString which should be avoidedColleencollege
H
4

I want to share my solution for ObjC, this is just a trick but works as expected for me.

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // this just convert view to `UIImage`
    UIImage *(^imageWithView)(UIView *) = ^(UIView *view) {

        UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
        [view.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    };

    // This is where the magic happen,
    // The width and height must be dynamic (it's up to you how to implement it)
    // to keep the alignment of the label in place
    //
    UIColor *(^getColorWithLabelText)(NSString*, UIColor*, UIColor*) = ^(NSString *text, UIColor *textColor, UIColor *bgColor) {

        UILabel *lbDelete = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 47, 40)];
        lbDelete.font = [UIFont boldSystemFontOfSize:11];
        lbDelete.text = text;
        lbDelete.textAlignment = NSTextAlignmentCenter;
        lbDelete.textColor = textColor;
        lbDelete.backgroundColor = bgColor;

        return [UIColor colorWithPatternImage:imageWithView(lbDelete)];
    };

    // The `title` which is `@"   "` is important it 
    // gives you the space you needed for the 
    // custom label `47[estimated width], 40[cell height]` on this example
    //
    UITableViewRowAction *btDelete;
    btDelete = [UITableViewRowAction
                rowActionWithStyle:UITableViewRowActionStyleDestructive
                title:@"   "
                handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
                    NSLog(@"Delete");
                    [tableView setEditing:NO];
                }];
    // Implementation
    //
    btDelete.backgroundColor = getColorWithLabelText(@"Delete", [UIColor whiteColor], [YJColor colorWithHexString:@"fe0a09"]);

    UITableViewRowAction *btMore;
    btMore   = [UITableViewRowAction
                rowActionWithStyle:UITableViewRowActionStyleNormal
                title:@"   "
                handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
                    NSLog(@"More");
                    [tableView setEditing:NO];
                }];
    // Implementation
    //
    btMore.backgroundColor = getColorWithLabelText(@"More", [UIColor darkGrayColor], [YJColor colorWithHexString:@"46aae8"]);

    return @[btMore, btDelete];
}

[YJColor colorWithHexString:<NSString>]; is just to convert hex string to UIColor.

Check the example output screenshot.
enter image description here

Haphtarah answered 24/1, 2017 at 6:35 Comment(0)
B
2

If you use XCode's Debug View Hierarchy to look what is happening in UITableView when the swipe buttons are active, you'll see that UITableViewRowAction items translates to button called _UITableViewCellActionButton, contained in UITableViewCellDeleteConfirmationView. One way to change button's properties is to intercept it when it's added to UITableViewCell. In your UITableViewCell derived class write something like this:

private let buttonFont = UIFont.boldSystemFontOfSize(13)
private let confirmationClass: AnyClass = NSClassFromString("UITableViewCellDeleteConfirmationView")!

override func addSubview(view: UIView) {
    super.addSubview(view)

    // replace default font in swipe buttons
    let s = subviews.flatMap({$0}).filter { $0.isKindOfClass(confirmationClass) }
    for sub in s {
        for button in sub.subviews {
            if let b = button as? UIButton {
                b.titleLabel?.font = buttonFont
            }
        }
    }
}
Boater answered 21/4, 2016 at 8:40 Comment(2)
Just a note: This uses a private API. It may get rejected, or you may have luck.Oxley
Don't know if this changed for iOS 11 or did in 10... but it looks like that's no longer the class getting added. In Xcode 9 I'm seeing a UISwipeActionStandardButton. As is with attempting to use Private API stuff, the min Apple changes it, your stuff no longer works.Embarkment
A
0

This seems to work, at least for setting the font color:

- (void)setupRowActionStyleForTableViewSwipes {
    UIButton *appearanceButton = [UIButton appearanceWhenContainedInInstancesOfClasses:@[[NSClassFromString(@"UITableViewCellDeleteConfirmationView") class]]];
    [appearanceButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
}
Algometer answered 22/3, 2016 at 23:8 Comment(0)
B
0

You could use UIButton.appearance to style the button inside the row action. Like so:

let buttonStyle = UIButton.appearance(whenContainedInInstancesOf: [YourViewController.self])

let font = UIFont(name: "Custom-Font-Name", size: 16.0)!
let string = NSAttributedString(string: "BUTTON TITLE", attributes: [NSAttributedString.Key.font : font, NSAttributedString.Key.foregroundColor : UIColor.green])

buttonStyle.setAttributedTitle(string, for: .normal)

Note: this will affect all of your buttons in this view controller.

Bilge answered 27/3, 2019 at 13:53 Comment(1)
Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made.Sclerotic
P
-1

Here is some Swift Code that might be helpful:

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) ->[AnyObject]? {

let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())] as Dictionary!
UIButton.appearance().setAttributedTitle(NSAttributedString(string: "Your Button", attributes: attributes), forState: .Normal)

// Things you do...

}

This will manipulate all buttons in your application.

Palenque answered 31/7, 2015 at 9:2 Comment(1)
Actually this will manipulate ALL buttons throughout your application. It appears that after this code is executed all buttons in the application are affected by this code. Not an ideal solution unless you don't have any other buttons in your application, which is probably not the case.Consecration
R
-1

I think you can use this method to change the appearance only in one (or more, you can define it) viewcontrollers:

    //create your attributes however you want to
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())] as Dictionary!            

   //Add more view controller types in the []
    UIButton.appearanceWhenContainedInInstancesOfClasses([ViewController.self])

Hope this helped.

Regulation answered 2/1, 2016 at 11:38 Comment(0)
K
-1
//The following code is in Swift3.1
    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
    {
        let rejectAction = TableViewRowAction(style: UITableViewRowActionStyle.default, title: "\u{2715}\nReject") { action, indexPath in
                print("didtapReject")
            }
            rejectAction.backgroundColor = UIColor.gray
            let approveAction = TableViewRowAction(style: UITableViewRowActionStyle.default, title: "\u{2713}\nApprove") { action, indexPath in
                print("didtapApprove")
            }
            approveAction.backgroundColor = UIColor.orange
            return [rejectAction, approveAction]
       }
Kennakennan answered 11/5, 2017 at 5:32 Comment(1)
This doesn't seem to change the font color at all.Caulfield
D
-18

How to use a custom font?

It's pretty easy.

  1. Firstly, you need to include your custom font files to your project.
  2. Next, go to your info.plist file and add a new entry with the key "Fonts provided by application". Note that this entry should be an Array.
  3. Then add the names of these files as elements of this array.

And that's it! All you need then is to use the font by its name like this

cell.textLabel.font = [UIFont fontWithName:@"FontName" size:16];

How to change the font color?

Even easier. All you need is

cell.textlabel.textcolor = UIColor.redColor()

Edit:

In your case you want to change the font of the RowAction. So I think of only 2 solutions. One to use [UIColor colorWithPatterImage:]

Or you can user [[UIButton appearance] setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; because the RowAction contains a button.

Dorsett answered 14/3, 2015 at 15:39 Comment(14)
Thank you, but this is not the right answer what I need. You help me implement custom font, that I know. I need set color/font for the cell in UITableViewActionRow. (the pink here: https://www.dropbox.com/s/jaineb3qgcezm90/Screenshot%202015-03-15%2009.14.51.png?dl=0) The code what you wrote me not working, because in the action what you can see in my first post here, you can work just with "title" but the title is reserved for localization only. Any idea how to fix it?Skeie
OMG! You made my day buddy! Thanks. I just rewrote your code to the Swift version and all working perfectly. UIButton.appearance().setTitleColor(UIColor.orangeColor(), forState: UIControlState.Normal) EDIT: And do you know, how I set the custom font for the button? I can't find function like "setTitleFont" there.Skeie
I guess something like the following: NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:@"YOURFONT" size:14], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, nil]; [[UIButton appearance] setTitleTextAttributes:attributes];Dorsett
Do you know the code in Swift? I can't do that without errors. :/Skeie
I guess it would be something like this ` let attributes: Dictionary = [NSFontAttributeName: UIFont(name: "HelveticaNeue-Light", size: 19)!] UIButton.appearance().setValuesForKeysWithDictionary(attributes)`Dorsett
The app crash, if I paste the code. And one more thing here: this scope is for all buttons in the app. Can I specified it just for the "Delete" button?Skeie
Sadly, I can get a hand on the reference. We are making a workaround. Try this line UIButton.appearance().setValueForKeyPath and your keyPath is Button.fontDorsett
I can't use setValueForKeyPath on the button, it works for you?.... I'm trying something like this UIButton.appearance().titleLabel?.font = UIFont(name: "Futura", size: 40) but still not working, is it without error, but the size and font is still on default.Skeie
Hey buddy, any idea there? :)) Thanks a lot!Skeie
Hey, pal! Sorry was a heavy day for me. Will dig that for you. :)Dorsett
I have found a solution that you may not like. You can adjust the appearance of UILabel as well to include the font.Dorsett
I'm not understand what you mean now. Can you show me? I want just change the font, with easy way like the font color.Skeie
Try this one UILabel.appearance().font = UIFont(name: "", size: 17)Dorsett
Yep, that is not optimal solution, but still not working. I'm just trying it right now and doesn't work. :(Skeie

© 2022 - 2024 — McMap. All rights reserved.