简体   繁体   English

iOS 11 中的 UILabel 错误自动换行

[英]UILabel wrong word wrap in iOS 11

I have problem with application using XIBs without autolayout.我在没有自动布局的情况下使用 XIB 的应用程序有问题。 I don't know if this is important information.我不知道这是否是重要信息。

I have UILabel with 2 lines using word wrap.我有 2 行的 UILabel 使用自动换行。 In iOS 10 word wrap was working correctly, and first line contained one word + special character, for example ampersand.在 iOS 10 中自动换行工作正常,第一行包含一个单词 + 特殊字符,例如&符号。 Example:例子:

ios 10 上的 UiLabel

Then on iOS 11 word wrap is working somehow wrong and puts ampresand to the second line:然后在 iOS 11 上,自动换行出现了某种错误,并将和号放在第二行:

ios 11 上的 UiLabel

This is problematic as longer words, that normally fitted on second line now are not being shown correctly.这是有问题的,因为通常安装在第二行的较长单词现在无法正确显示。 Any idea what has changed?知道发生了什么变化吗? I know about safeArea but it doesn't look like reason.我知道 safeArea 但它看起来不像是原因。 Any ideas how to move that ampersand to the top where is plenty of space for it?任何想法如何将那个&符号移动到有足够空间的顶部?

Rest of the settings:其余设置: 尺寸检查员

This could very likely be an intentional change by Apple to prevent widowed lines.这很可能是 Apple 为防止寡妇行而有意进行的更改。 From a design perspective, it is preferred to avoid having a single word on a line of text.从设计的角度来看,最好避免在一行文本中出现一个单词。 So it seems that UILabel now breaks the line in a way that the second line of text always has at least 2 words on it.因此,现在 UILabel 似乎以第二行文本始终至少包含 2 个单词的方式换行。

It is surprising that there is no documentation or way to disable this behavior though.令人惊讶的是,没有文档或方法可以禁用此行为。

在此处输入图片说明

Also here's a good article about "widowed" and "orphaned" text.这里还有一篇关于“寡居”和“孤儿”文本的好文章

Launching the app with the arguments -NSAllowsDefaultLineBreakStrategy NO (an undocumented defaults setting) seems to force back to the old behavior.使用参数-NSAllowsDefaultLineBreakStrategy NO (未记录的默认设置)启动应用程序似乎会强制回到旧行为。 Alternatively, you can set NSAllowsDefaultLineBreakStrategy to NO in NSUserDefaults at startup (Apple registers a default of YES for that value when UILabel or the string drawing code is initialized, it appears, so you would need to register an overriding value after that, or insert it into the NSArgumentDomain , or just set the default persistently).另外,您也可以设置NSAllowsDefaultLineBreakStrategyNONSUserDefaults启动时(苹果公司注册的默认YES时,该值UILabel或串绘图代码被初始化,它的出现,所以你需要在那之后注册一个高于一切的价值,或者将其插入进入NSArgumentDomain ,或者只是永久设置默认值)。

Apple may consider that private API and reject apps that use it; Apple 可能会考虑该私有 API 并拒绝使用它的应用程序; I'm not sure.我不知道。 I have not tried this in a shipping app.我没有在运输应用程序中尝试过这个。 However, it does work in quick testing -- saw the setting in NSUserDefaults and found changing it altered the behavior.然而,它在快速测试中确实有效——看到NSUserDefaults的设置并发现改变它改变了行为。

Since iOS 14 you can use lineBreakStrategy property of UILabel instance to control this behavior.从 iOS 14 开始,您可以使用UILabel实例的lineBreakStrategy属性来控制此行为。

Available values are:可用值为:

NSParagraphStyle.LineBreakStrategy() // none
NSParagraphStyle.LineBreakStrategy.pushOut
NSParagraphStyle.LineBreakStrategy.hangulWordPriority
NSParagraphStyle.LineBreakStrategy.standard

To disable this behavior using Swift:要使用 Swift禁用此行为:

if #available(iOS 14.0, *) {
    label.lineBreakStrategy = []
}

// Alternatives
// label.lineBreakStrategy = NSParagraphStyle.LineBreakStrategy()
// label.lineBreakStrategy = .init(rawValue: 0)
// label.lineBreakStrategy = .init()

Objective-C:目标-C:

if (@available(iOS 14.0, *)) {
    label.lineBreakStrategy = NSLineBreakStrategyNone;
}

This is not really an answer, but I want to add an illustration of how it is a general problem, not at all related to ampersands.这不是真正的答案,但我想补充说明这是一个普遍问题,与&符号完全无关。

两个 UILabel

Both of these UILabels have identical width constraints, and the text is almost identical.这两个 UILabel 具有相同的宽度约束,并且文本几乎相同。 But the second has the word wrap I would expect.但是第二个有我期望的自动换行。 The first is incorrect, the "about" can clearly stay on the first line.第一个不正确,“关于”可以清楚地留在第一行。

It seems that replacing the space before the ampersand with a non-breaking space (U+00A0) keeps the ampersand on the same line.似乎用不间断空格(U + 00A0)替换与号之前的空格使与号保持在同一行上。 Depending on how you are generating the text for the label, this might not be easy to automate (maybe you really do need the ampersand to be on the second line in some cases).根据您为标签生成文本的方式,这可能不容易自动化(在某些情况下,您可能确实需要将与号放在第二行)。

An option may be to use a UITextView instead -- that does not seem to have this behavior.一个选项可能是使用 UITextView 代替 - 似乎没有这种行为。 If you set the NSTextContainer.lineFragmentPadding to 0, the textContainerInset to UIEdgeInsetsZero, and turn off all scrolling (scrollEnabled, bounces, scroll indicators, etc.) it will display similarly to a UILabel, though not with as much constraint flexibility.如果将 NSTextContainer.lineFragmentPadding 设置为 0,将 textContainerInset 设置为 UIEdgeInsetsZero,并关闭所有滚动(scrollEnabled、反弹、滚动指示器等),它将显示类似于 UILabel,但没有那么多的约束灵活性。 It's not a drop-in replacement, but in some situations it's acceptable.这不是直接替换,但在某些情况下它是可以接受的。

A bit of a hack but you can add some zero width spaces to the end of the string to restore the old behaviour, without affecting the layout of the string otherwise that you'd get from normal spaces:有点小技巧,但您可以在字符串末尾添加一些零宽度空格以恢复旧行为,而不会影响字符串的布局,否则您会从普通空格中获得:

let zeroWidthSpace: Character = "\u{200B}"
let spacingForWordWrapping = String(repeating: zeroWidthSpace, count: 6)
label.text = "oneText & two" + spacingForWordWrapping

As a simple (hacky) workaround, you can often get the correct behaviour with a UILabel by adding spaces at the end of your text.作为一种简单(hacky)的解决方法,您通常可以通过在文本末尾添加空格来使用 UILabel 获得正确的行为。 Using your example:使用您的示例:

Wraps the new (undesired) way:包装新的(不需要的)方式:
"oneText & two."

Wraps the old way:包装旧方式:
"oneText & two. " (note the 2 extra spaces at the end of the string) "oneText & two. " (注意字符串末尾的 2 个额外空格)

The obvious downside is if those extra spaces get forced to a new line by themselves, but for something simple like a title it's often enough.明显的缺点是,如果这些额外的空格被自己强制换行,但对于像标题这样简单的东西,通常就足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM