【问题标题】:UIAlertController custom font doesn't work at iOSUIAlertController 自定义字体在 iOS 上不起作用
【发布时间】:2016-05-24 06:35:38
【问题描述】:

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

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

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

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

    • 仅适用于首次显示ActionSheet。从第二次开始,它不起作用

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

第二次尝试 下面的代码也不能正常工作。

  • 当我把代码放在[Block 2]上时

    • 短时间显示默认字体后,显示自定义字体
  • 当我把代码放在[Block 3]上时

    • 它仅适用于 cancel 按钮

FindDescendantViews&lt;UILabel&gt;()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) 吗?
  • 我的第二次尝试和你的代码有什么区别? @JigarTarsariya
  • 你看过UIAppearance protocol吗?
  • 你的意思是我的第一次尝试? (UILabel.AppearanceWhenContainedIn) @Brett Donald

标签: c# ios xamarin.ios uialertcontroller


【解决方案1】:

UIAlertController UILabels 字体和颜色可以通过 KVC 使用 attributedTitle 键设置。在[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)
        }
    }
}

【讨论】:

【解决方案2】:

不允许继承或更改 UIAlertController 的默认内容。您需要为其制作自定义视图。

【讨论】:

    【解决方案3】:

    我这里有解决方案。我创建了一个自定义的 AlertThemeConfigurator,它递归地运行所有子视图以查找 UILabel,然后在它们上设置主题的属性文本,用于标题、消息和不同类型的操作。随意适当地设置属性字符串的样式。

    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)
    

    【讨论】:

    • 我认为根据 Apple 的指南,不允许子类化 UIAlertController。
    • 我刚刚更新了不从 UIAlertViewController 继承的解决方案 :) 希望这会有所帮助
    • @BhavukJain 我刚刚又更新了一次,并创建了一个私有类来执行标签主题化,这样方法就不会暴露了
    • @BhavukJain 刚刚意识到我有一个类型,没有在 AlertLabelConfigurator 上调用 adjustLabels。修好了
    猜你喜欢
    • 2012-10-17
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    • 2013-07-23
    • 1970-01-01
    相关资源
    最近更新 更多