如何在UITableViewRowAction中自定义字体和颜色,不使用Storyboard

11

我有一个传统的TableView,你可以在滑动并点击按钮后删除其中的项目。我知道如何在单元格上设置自定义背景,但是我不知道如何设置自定义字体和颜色。

谢谢您的帮助!

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

请查看我在这篇帖子中的答案:https://dev59.com/8V8d5IYBdhLWcg3wYhWX#36145706 - Lee Andrew
9个回答

11

嗯,我找到的设置自定义字体的唯一方法是使用UIAppearance协议的appearanceWhenContainedIn方法。这个方法目前在Swift中还没有,所以你需要用Objective-C来实现。

我创建了一个实用的Objective-C类方法来设置它:

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

这样做虽然可行,但绝不是理想的。如果您没有在包含层次结构中包括UIView,则会影响披露指示器(我甚至没有意识到披露指示器是UIButton子类)。此外,如果您的单元格中有一个位于单元格子视图中的UIButton,那么该按钮也会受到此解决方案的影响。

考虑到这些复杂性,可能更好的选择是使用更多自定义选项的开源库之一来进行表格单元格滑动操作。


4
我想到了一个改进这个答案的方法,避免影响单元格中其他按钮。在检查扩展单元格的视图层次结构后,我发现删除按钮位于 UITableViewCellDeleteConfirmationView 视图内部。尽管这是私有 API,但使用它而不是 UIView 可以仅针对删除按钮进行操作,而不会影响单元格中的其他按钮。因此,可以使用 [NSClassFromString(@"UITableViewCellDeleteConfirmationView") class] 代替 [UIView class] - Dima
@Dima 你能确认一下你的应用是否通过了审核,还是因为使用了私有 API 被拒绝了? - Septronic
这是一段时间以前的事情了,我的应用程序已经通过了多次审核而没有出现任何问题。 - Dima
如何以这种方式添加更多的按钮? - guhan0
在按照 https://nshipster.com/uiappearance/ 进行 grep 操作后,似乎无法使用 setAttributedTitle:forState: 来自定义 UIButton。您能确认这个答案仍然有效吗? - henrique
2
对我来说不起作用,至少在iOS 12上是这样。该按钮包含在名为UISwipeActionPullView的私有类视图中,因此您必须使用NSClassFromString,但应避免使用它。 - user2378197

4
我想分享我的解决方案给ObjC,这只是一个技巧,但对我来说效果很好。
- (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>]; 是将十六进制字符串转换为 UIColor 的方法。

请查看以下示例输出截图。
enter image description here


2

如果你使用XCode的Debug View Hierarchy来查看UITableView在滑动按钮处于活动状态时发生了什么,你会发现UITableViewRowAction项目被转换为一个名为_UITableViewCellActionButton的按钮,包含在UITableViewCellDeleteConfirmationView中。改变按钮属性的一种方法是在它被添加到UITableViewCell时拦截它。在你的UITableViewCell派生类中编写如下内容:

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

1
请注意:这使用了私有 API。它可能会被拒绝,或者你可能会有好运。 - Frederik Winkelsdorf
不知道这是否在iOS 11中有所改变或者在10中已经改变了...但是看起来那个类不再被添加了。在Xcode 9中,我看到了一个UISwipeActionStandardButton。就像尝试使用私有API一样,如果苹果公司进行最小的更改,你的东西就不再起作用了。 - jhelzer

0

这似乎可以工作,至少可以设置字体颜色:

- (void)setupRowActionStyleForTableViewSwipes {
    UIButton *appearanceButton = [UIButton appearanceWhenContainedInInstancesOfClasses:@[[NSClassFromString(@"UITableViewCellDeleteConfirmationView") class]]];
    [appearanceButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
}

0
你可以使用 UIButton.appearance 来设置行动中按钮的样式。像这样:
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)

注意:这将影响此视图控制器中所有的按钮

感谢您提供这段代码片段,它可能会提供一些有限的、即时的帮助。通过展示为什么这是一个好的问题解决方案,合适的解释将极大地提高其长期价值,并使其对未来具有相似问题的读者更加有用。请编辑您的答案,添加一些解释,包括您所做的假设。 - Dwhitz

-1
我认为你可以使用这种方法仅在一个(或多个,你可以定义)视图控制器中改变外观:
    //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])

希望这有所帮助。

-1

这里有一些可能有用的 Swift 代码:

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

}

这将操作您应用程序中的所有按钮。


4
实际上,这将影响应用程序中的所有按钮。执行此代码后,应用程序中的所有按钮都会受到该代码的影响。这不是理想的解决方案,除非您的应用程序中没有其他按钮,但这可能不是情况。 - northdig

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

这似乎根本没有改变字体颜色。 - Travis M.

-18

如何使用自定义字体?

这很容易。

  1. 首先,您需要将自定义字体文件包含到您的项目中。
  2. 接下来,进入您的info.plist文件并添加一个新条目,键为“应用提供的字体”。请注意,此条目应为数组。
  3. 然后将这些文件的名称作为该数组的元素添加。

就是这样!您所需的只是按其名称使用字体,如下所示:

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

如何更改字体颜色?

更简单。您所需的只是

cell.textlabel.textcolor = UIColor.redColor()

编辑:

在您的情况下,您想要更改RowAction的字体。因此,我想到了只有两个解决方案。一种是使用[UIColor colorWithPatterImage:]

或者您可以使用[[UIButton appearance] setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];,因为RowAction包含一个按钮。


谢谢你,但这不是我需要的正确答案。你帮我实现了自定义字体,这点我知道。我需要为UITableViewActionRow中的单元格设置颜色/字体。(就像这里的粉色:https://www.dropbox.com/s/jaineb3qgcezm90/Screenshot%202015-03-15%2009.14.51.png?dl=0) 你写给我的代码不起作用,因为在我第一篇帖子中所看到的操作中,你只能使用“title”,但“title”仅保留用于本地化。有什么想法如何解决它? - Vlastimil Fiser
1
哇!伙计,你让我的一天都变得美好了!谢谢。我刚刚将你的代码改写成了Swift版本,现在一切都完美运行。UIButton.appearance().setTitleColor(UIColor.orangeColor(), forState: UIControlState.Normal) 编辑: 你知道怎么为按钮设置自定义字体吗?我找不到像“setTitleFont”这样的函数。 - Vlastimil Fiser
我猜应该是这样的代码:NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:@"YOURFONT" size:14], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, nil]; [[UIButton appearance] setTitleTextAttributes:attributes]; - Ashraf Tawfeeq
你知道Swift的代码吗?我做不到没有错误。:/ - Vlastimil Fiser
1
我无法在按钮上使用 setValueForKeyPath,你可以用吗?我正在尝试像这样的代码 UIButton.appearance().titleLabel?.font = UIFont(name: "Futura", size: 40),但仍然不起作用,没有错误提示,但字体大小仍然是默认值。 - Vlastimil Fiser
显示剩余9条评论

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