UIAlertController自定义字体在iOS上无法正常工作

9

UIAlertController自定义字体不能正常工作。

下面的代码是一个名为ShowActionSheetAsync的函数,它显示一个ActionSheet。在这个时候,我想改变ActionSheet的字体。我尝试了几种方法,但效果不佳。有没有更好的解决方案?

public Task<bool> ShowActionSheetAsync()
{
    var source = new TaskCompletionSource<bool>();
    var alert = new UIAlertController
    {
        Title = "title"
    };
    alert.AddAction(UIAlertAction.Create(
            "button1",
            UIAlertActionStyle.Default,
            _ => source.SetResult(true)));
    alert.AddAction(UIAlertAction.Create(
        "cancel",
        UIAlertActionStyle.Cancel,
        _ => source.SetResult(false)));

    // [Block 1]
    var viewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
    ViewController.PresentViewController(alert, true, delegate
    {
        // [Block 2]
    });

    // [Block 3]
    return source.Task;
}

第一次尝试 以下代码无法正常工作。

  • 当我将代码放在[块1][块2]上时

    • 它根本不起作用
  • 当我将代码放在[块3]上时

    • 仅在第一次显示ActionSheet时应用。从第二次开始,它就不起作用了

UILabel.AppearanceWhenContainedIn(typeof(UIActionSheet)).Font = UIFont.FromName(StyleResources.MediumFontName, 20);

第二次尝试 以下代码也无法正常工作。

  • 当我将代码放在[块2]上时

    • 默认字体会已经显示一小段时间后才显示自定义字体
  • 当我将代码放在[块3]上时

    • 它只在取消按钮上运行

FindDescendantViews<UILabel>()UIView的扩展方法,返回所有适当类型的子视图。

var labels = alert.View.FindDescendantViews<UILabel>();
foreach (var label in labels)
{
    label.Font = UIFont.FromName(StyleResources.MediumFontName, 20);
}

你是否已经尝试过 label.Font = UIFont(name: StyleResources.MediumFontName, size: 20) - Jigar Tarsariya
我的第二次尝试和你的代码有什么不同?@JigarTarsariya - wplong11
你有研究过 UIAppearance 协议 吗? - Brett Donald
你是指我的第一次尝试吗?(UILabel.AppearanceWhenContainedIn)@Brett Donald - wplong11
3个回答

1

不允许对UIAlertController进行子类化或更改默认设置。您需要为其创建自定义视图。


1

UIAlertController UILabels的字体和颜色可以通过使用attributedTitle键进行KVC设置。在[Block 3]中使用此方法。

func changeAlert(alert: UIAlertController, backgroundColor: UIColor, textColor: UIColor, buttonColor: UIColor?) {
    let view = alert.view.firstSubview().firstSubview()
    view.backgroundColor = backgroundColor
    view.layer.cornerRadius = 10.0

    // set color to UILabel font
    setSubviewLabelsToTextColor(textColor, view: view)

    // set font to alert via KVC, otherwise it'll get overwritten
    let titleAttributed = NSMutableAttributedString(
        string: alert.title!,
        attributes: [NSFontAttributeName:UIFont.boldSystemFontOfSize(17)])
    alert.setValue(titleAttributed, forKey: "attributedTitle")


    let messageAttributed = NSMutableAttributedString(
        string: alert.message!,
        attributes: [NSFontAttributeName:UIFont.systemFontOfSize(13)])
    alert.setValue(messageAttributed, forKey: "attributedMessage")


    // set the buttons to non-blue, if we have buttons
    if let buttonColor = buttonColor {
        alert.view.tintColor = buttonColor
    }
}

func setSubviewLabelsToTextColor(textColor: UIColor, view:UIView) {
    for subview in view.subviews {
        if let label = subview as? UILabel {
            label.textColor = textColor
        } else {
            setSubviewLabelsToTextColor(textColor, view: subview)
        }
    }
}

这不是关于我的问题的解决方案。我想要更改按钮样式(字体),而不是标题和消息样式。 - wplong11
看看这个 https://dev59.com/Yl8d5IYBdhLWcg3wxUjC 顺便提一下,KVC是Key-Value Coding https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/Overview.html#//apple_ref/doc/uid/20001838-SW1 - Pau Senabre

1
我这里有解决方案。我创建了一个自定义的AlertThemeConfigurator,它会递归地遍历所有子视图,寻找UILabels,然后为标题、消息和不同类型的操作设置主题属性文本。请随意适当地样式化属性字符串。
class AlertThemeConfigurator {

   class func configureAlertViewController(alertController : UIAlertController) {
        AlertLabelConfigurator.adjustLabels(inView: alertController.view, alertController: alertController)
   }

   class AlertLabelConfigurator {

       class func adjustLabels(inView view : UIView, alertController : UIAlertController) {
            for subview in view.subviews {

                if subview is UILabel {
                    adjustLabel((subview as! UILabel), inAlertViewController : alertController)
                }

                adjustLabels(inView :subview,  alertController : alertController)
            }
       }

       class func adjustLabel(label : UILabel, inAlertViewController alertController : UIAlertController) {
            if label.text == alertController.title {
                label.attributedText = attributedTitle(label.text!)
            } else if label.text == alertController.message {
                label.attributedText = attributedBody(label.text!)
            }

            for action in alertController.actions {
                if label.text == action.title {
                    switch action.style {
                    case .Default:
                        label.attributedText = attributedDefaultAction(action.title!)
                    case .Cancel:
                        label.attributedText = attributedCancelAction(action.title!)
                    case .Destructive:
                        label.attributedText = attributedDestructiveAction(action.title!)
                    }
                }
            }
        }

        class func attributedTitle(title : String) -> NSAttributedString {
             let attributes = [NSFontAttributeName:UIFont(name: "Avenir-Medium", size: 20)!, NSForegroundColorAttributeName :  UIColor.greenColor()]
             return NSAttributedString(string: title, attributes: attributes)
        }

        class func attributedBody(title : String) -> NSAttributedString {
             let attributes = [NSFontAttributeName:UIFont(name: "Avenir-Medium", size: 12)!, NSForegroundColorAttributeName :  UIColor.orangeColor()]
             return NSAttributedString(string: title, attributes: attributes)
        }

        class func attributedDefaultAction(title : String) -> NSAttributedString {
             let attributes = [NSFontAttributeName:UIFont(name: "Avenir-Medium", size: 14)!, NSForegroundColorAttributeName :  UIColor.yellowColor()]
             return NSAttributedString(string: title, attributes: attributes)
        }

        class func attributedCancelAction(title : String) -> NSAttributedString {
             let attributes = [NSFontAttributeName:UIFont(name: "Avenir-Medium", size: 14)!, NSForegroundColorAttributeName :  UIColor.purpleColor()]
             return NSAttributedString(string: title, attributes: attributes)
        }

        class func attributedDestructiveAction(title : String) -> NSAttributedString {
             let attributes = [NSFontAttributeName:UIFont(name: "Avenir-Medium", size: 14)!, NSForegroundColorAttributeName :  UIColor.redColor()]
             return NSAttributedString(string: title, attributes: attributes)
        }
    }
}

呈现它时,请调用:

 let alert = CustomAlertController(title: "Title", message:"Message" , preferredStyle: UIAlertControllerStyle.ActionSheet)
 alert.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil))
 presentViewController(alert, animated: true, completion: nil)
 AlertThemeConfigurator.configureAlertViewController(alert)

根据苹果的指导方针,我认为不允许对UIAlertController进行子类化。 - Bhavuk Jain
我刚刚更新了解决方案,不再继承自UIAlertViewController :) 希望这可以帮到你。 - AntonTheDev
@BhavukJain 我刚刚更新了一次,并创建了一个私有类来执行标签主题,以便方法不会被公开。 - AntonTheDev
@BhavukJain 刚刚意识到我在那里打错了一个字,没有在 AlertLabelConfigurator 上调用 adjustLabels。已经修复了。 - AntonTheDev

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