UIButton 上的 iOS NSAttributedString
Posted
技术标签:
【中文标题】UIButton 上的 iOS NSAttributedString【英文标题】:iOS NSAttributedString on UIButton 【发布时间】:2013-07-19 21:50:20 【问题描述】:我使用的是 iOS 6,所以属性字符串应该很容易使用,对吧?嗯……没那么多。
我想做什么:
使用UIButton
的自定义子类(它不会对titleLabel
执行任何自定义操作),我想要一个多行属性标题:
-
第一行全部大写(我意识到这不是属性的一部分)
粗体在第一行
下划线在第一行
第二行显示“正常”重量
第二行没有下划线
以两条线为中心
到目前为止,我已经能够得到 # 的 1 到 5(至少,我认为我做到了,但是当前的测试产生了多行文本的错误),但是当我尝试做某事时(任何事情! ) 使文本居中,我的应用程序不断崩溃。当我尝试让所有 6 项工作(通过各种方法)时,我收到以下崩溃/错误:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason:
'NSAttributedString invalid for autoresizing,
it must have a single spanning paragraph style
(or none) with a non-wrapping lineBreakMode.'
根据我的尝试,我似乎可以选择以下选项之一,但不能同时拥有:
-
多行居中标签
属性标签
如果我必须,我可以接受其中一个或另一个,但我不敢相信我不能拥有一个看似相当简单的概念。
谁能告诉我我做错了什么?
这是我正在尝试的代码的最后一次迭代:
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setAlignment:NSTextAlignmentCenter];
[style setLineBreakMode:NSLineBreakByWordWrapping];
UIFont *font1 = [UIFont fontWithName:@"HelveticaNeue-Medium" size:20.0f];
UIFont *font2 = [UIFont fontWithName:@"HelveticaNeue-Light" size:20.0f];
NSDictionary *dict1 = @NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle),
NSFontAttributeName:font1;
NSDictionary *dict2 = @NSUnderlineStyleAttributeName:@(NSUnderlineStyleNone),
NSFontAttributeName:font2;
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init];
[attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"LINE 1\n" attributes:dict1]];
[attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"line 2" attributes:dict2]];
[[self buttonToStyle] setAttributedTitle:attString forState:UIControlStateNormal];
[[[self buttonToStyle] titleLabel] setNumberOfLines:0];
[[[self buttonToStyle] titleLabel] setLineBreakMode:NSLineBreakByWordWrapping];
【问题讨论】:
如何设置 UILabel 的样式并将其添加到按钮中?titleLabel
不应该是UILabel
吗?我想我可以做到这一点,但我仍然觉得这是一个比应该需要的更大的锤子。
这是 ios,没有任何意义......我的孩子。前段时间我把 NSMutableAttributedString 搞砸了,这不过是头疼。我的建议是让事情尽可能简单易行。
我不反对,但我仍然坚持我的愿望,如上所述,并不完全是“尖端”! ;-) 我不明白为什么我可以用股票UILabel
做到这一点,但它显然在UIButton
上不起作用。奇怪的。看看你的想法是否可行。
@JeffCompton 所以......你的答案很完美!不过,我仍然不喜欢这个解决方案。感觉“笨拙”和错误。我不是在争论它的功效,只是说它不应该是必要的。谢谢您的帮助!如果您将您的评论包装为答案,我会接受它(除非有人给我一种“本机”做我想做的事情的方法)。
【参考方案1】:
在我看来,您好像忘记在代码中使用您设置的“样式”对象......您只是实例化了它。您应该将代码修改为如下所示:
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setAlignment:NSTextAlignmentCenter];
[style setLineBreakMode:NSLineBreakByWordWrapping];
UIFont *font1 = [UIFont fontWithName:@"HelveticaNeue-Medium" size:20.0f];
UIFont *font2 = [UIFont fontWithName:@"HelveticaNeue-Light" size:20.0f];
NSDictionary *dict1 = @NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle),
NSFontAttributeName:font1,
NSParagraphStyleAttributeName:style; // Added line
NSDictionary *dict2 = @NSUnderlineStyleAttributeName:@(NSUnderlineStyleNone),
NSFontAttributeName:font2,
NSParagraphStyleAttributeName:style; // Added line
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init];
[attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"LINE 1\n" attributes:dict1]];
[attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"line 2" attributes:dict2]];
[self.resolveButton setAttributedTitle:attString forState:UIControlStateNormal];
[[self.resolveButton titleLabel] setNumberOfLines:0];
[[self.resolveButton titleLabel] setLineBreakMode:NSLineBreakByWordWrapping];
请注意,我只添加了定义 NSParagraphStyleAttributeName 的行。其他一切都相同。这就是我得到的按钮:
这里是 Swift 3.0
let style = NSMutableParagraphStyle()
style.alignment = .center
style.lineBreakMode = .byWordWrapping
guard
let font1 = UIFont(name: "HelveticaNeue-Medium", size: 20),
let font2 = UIFont(name: "HelveticaNeue-Light", size: 20) else return
let dict1:[String:Any] = [
NSUnderlineStyleAttributeName:NSUnderlineStyle.styleSingle.rawValue,
NSFontAttributeName:font1,
NSParagraphStyleAttributeName:style
]
let dict2:[String:Any] = [
NSUnderlineStyleAttributeName:NSUnderlineStyle.styleNone.rawValue,
NSFontAttributeName:font2,
NSParagraphStyleAttributeName:style
]
let attString = NSMutableAttributedString()
attString.append(NSAttributedString(string: "LINE 1", attributes: dict1))
attString.append(NSAttributedString(string: "line 2", attributes: dict2))
button.setAttributedTitle(attString, for: .normal)
button.titleLabel?.numberOfLines = 0
button.titleLabel?.lineBreakMode = .byWordWrapping
【讨论】:
当我使用属性文本时,有人有解决方案吗? ***.com/questions/24525224/…,我在这里得到了答案。 如何添加颜色? 我知道了NSForegroundColorAttributeName: UIColor.white
如果不使用下划线样式,需要在第1行和第2行之间加一个'\n'字符强制换行。【参考方案2】:
在 Swift 5.1 和 iOS 13.1 中,您可以使用下面的 UIButton
子类实现来解决您的问题:
import UIKit
class CustomButton: UIButton
required init(title: String, subtitle: String)
super.init(frame: CGRect.zero)
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
style.lineBreakMode = NSLineBreakMode.byWordWrapping
let titleAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.foregroundColor: UIColor.label,
NSAttributedString.Key.underlineStyle : NSUnderlineStyle.single.rawValue,
NSAttributedString.Key.font : UIFont.preferredFont(forTextStyle: UIFont.TextStyle.largeTitle),
NSAttributedString.Key.paragraphStyle : style
]
let subtitleAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.label,
NSAttributedString.Key.font : UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body),
NSAttributedString.Key.paragraphStyle : style
]
let attributedString = NSMutableAttributedString(string: title, attributes: titleAttributes)
attributedString.append(NSAttributedString(string: "\n"))
attributedString.append(NSAttributedString(string: subtitle, attributes: subtitleAttributes))
setAttributedTitle(attributedString, for: UIControl.State.normal)
titleLabel?.numberOfLines = 0
titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
用法:
import UIKit
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
let button = CustomButton(title: "Title", subtitle: "Subtitle")
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
let horizontalConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
如果您确实需要system
类型的按钮,也可以使用以下代码:
import UIKit
extension UIButton
static func customSystemButton(title: String, subtitle: String) -> UIButton
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center
style.lineBreakMode = NSLineBreakMode.byWordWrapping
let titleAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.underlineStyle : NSUnderlineStyle.single.rawValue,
NSAttributedString.Key.font : UIFont.preferredFont(forTextStyle: UIFont.TextStyle.largeTitle),
NSAttributedString.Key.paragraphStyle : style
]
let subtitleAttributes = [
NSAttributedString.Key.font : UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body),
NSAttributedString.Key.paragraphStyle : style
]
let attributedString = NSMutableAttributedString(string: title, attributes: titleAttributes)
attributedString.append(NSAttributedString(string: "\n"))
attributedString.append(NSAttributedString(string: subtitle, attributes: subtitleAttributes))
let button = UIButton(type: UIButton.ButtonType.system)
button.setAttributedTitle(attributedString, for: UIControl.State.normal)
button.titleLabel?.numberOfLines = 0
button.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
return button
用法:
import UIKit
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
let button = UIButton.customSystemButton(title: "Title", subtitle: "Subtitle")
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
let horizontalConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
下面的两个屏幕截图显示了UIButton
子类(左侧)和system
类型按钮(右侧)的结果显示:
【讨论】:
【参考方案3】:Swift 5.1
中的两行 UIButton
和 NSAttributedString
标题:
func customizeSubscribeButton()
subscribeButton.titleLabel?.numberOfLines = 2
let title = NSMutableAttributedString()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let part1 = NSAttributedString(string: "SUBSCRIBE FOR 12 MONTH\n",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 24, weight: .semibold),
NSAttributedString.Key.paragraphStyle: paragraphStyle])
let part2 = NSAttributedString(string: "999.00 RUB ECONOMY 85%",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12, weight: .light),
NSAttributedString.Key.paragraphStyle: paragraphStyle])
title.append(part1)
title.append(part2)
subscribeButton.setAttributedTitle(title, for: .normal)
【讨论】:
以上是关于UIButton 上的 iOS NSAttributedString的主要内容,如果未能解决你的问题,请参考以下文章
UIButton 上的 iOS NSAttributedString
iOS - UIPageControl 上的 UIButton 不起作用