【问题标题】:UILabel wrong word wrap in iOS 11iOS 11 中的 UILabel 错误自动换行
【发布时间】:2017-09-13 14:21:17
【问题描述】:

我在使用没有自动布局的 XIB 的应用程序时遇到问题。我不知道这是否是重要信息。

我有 2 行使用自动换行的 UILabel。在 iOS 10 中,自动换行正常工作,第一行包含一个单词 + 特殊字符,例如 & 符号。示例:

然后在 iOS 11 上,自动换行出现了某种错误,并将 & 放在第二行:

这是有问题的,因为通常安装在第二行的较长单词现在没有正确显示。知道发生了什么变化吗?我知道 safeArea 但它看起来不像是原因。任何想法如何将与符号移动到顶部有足够空间的地方?

其余设置:

【问题讨论】:

  • 我刚刚遇到了同样的问题,只能猜测:iOS 11 中的文本换行算法似乎发生了变化,因此结果更加平衡/看起来更加盒装。
  • 看起来我们也有同样的问题。这似乎是一个错误,因为 UILabel 历来被用于我们想要模拟典型文字处理器(或 Web 浏览器)自动换行的情况,而不是找出可以容纳所有文本的最小框。
  • 我看到了同样的问题(使用&符号)。如果我使用 Xcode 8(针对 iOS 10)构建应用程序,然后在 iOS 11 上运行该构建,我会看到新的自动换行行为。因此,即使在概念上提供与 iOS 10 应用程序的向后兼容性时,iOS 11 的自动换行也是不同的。
  • 我认为强制这种行为是一个错误,最终决定向 Apple 提交 36021540。如果有其他人提供文件,您可以参考这个。
  • 这个问题来自 ios 11

标签: ios iphone uilabel ios11


【解决方案1】:

这是 Apple 为防止寡行而做出的更改。从设计的角度来看,最好避免在一行文本中包含一个单词。 UILabel 现在以第二行文本始终至少包含 2 个单词的方式换行。

有关禁用它的选项,请参阅下面的答案。

这里还有a good article 关于“丧偶”和“孤儿”的文字。

【讨论】:

  • 经过测试,我可以得出结论,iOS 11 确实使用孤立词拉下了一个额外的词。
  • 我还可以在更改我的应用程序中的文本后验证 UILabels 的这种行为,它正确地包装了单词。
  • 哦,这很有趣。
  • 但只有两行标签?当总共有两行以上时,我看到它允许最后一行使用一个单词。
  • 我无法理解的是标签的宽度大于实际显示的文本。这样就不可能对齐,例如 2 行标签旁边的表情符号。
【解决方案2】:

使用参数-NSAllowsDefaultLineBreakStrategy NO(未记录的默认设置)启动应用程序似乎会强制恢复旧行为。或者,您可以在启动时将NSUserDefaults 中的NSAllowsDefaultLineBreakStrategy 设置为NO(当UILabel 或字符串绘图代码被初始化时,Apple 会为该值注册默认值YES,它会出现,因此您需要在此之后注册一个覆盖值,或者将其插入到NSArgumentDomain,或者只是永久设置默认值。

Apple 可能会考虑使用该私有 API 并拒绝使用它的应用;我不知道。我没有在运输应用程序中尝试过这个。但是,它在快速测试中确实有效——看到NSUserDefaults 中的设置并发现更改它会改变行为。

【讨论】:

  • 效果很好!将它添加到我的 UILabel 类别中进行初始化。 :-)
  • 实际上,只需在应用启动时将 NSAllowsDefaultLineBreakStrategy 设置为 false 就可以了!
  • 是的,这将覆盖 Apple 所做的 registerDefaults: 调用。这也将持续将其设置为用户默认值。您也可以将其放入字典中(最好从当前字典开始)并调用[defaults setVolatileDomain:dict forName:NSArgumentDomain],因此它相当于运行时参数——它不会在磁盘上持久化,但仍会覆盖 Apple。如果您只是在 UILabel drawRect 覆盖期间临时设置它,它甚至可能会起作用,使其仅在某些情况下使用。
  • 这确实适用于UserDefaults.standard.set(false, forKey: "NSAllowsDefaultLineBreakStrategy")。有人在运输应用程序中使用它吗?苹果是否拒绝了它?
【解决方案3】:

从 iOS 14 开始,您可以使用 UILabel 实例的 lineBreakStrategy 属性来控制此行为。

可用的值为:

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

要使用 Swift禁用此行为:

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

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

要使其在较低的 iOS 版本上运行,您可以使用 NSAttributedString:

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakStrategy = []

let attributedString = NSAttributedString(string: "Your text here", attributes: [
    .paragraphStyle: paragraphStyle
])

let label = UILabel()
label.attributedText = attributedString

目标-C:

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

【讨论】:

  • 非常感谢您发布此信息! (奇怪的是,Objective-C 版本更具可读性!)
  • @DavidDunham 我知道对吗?为什么 swift 没有 LineBreakStrategy.none?在某些方面,Swift 可能非常不直观,它面向年幼的孩子推销,让他们开始编码......
  • @derbs 这是一个选项集,因此您可以使用[]
  • 这应该是公认的答案。
  • 不要将其设置为 None (或 Swift 中的 [] )。这将删除其他值,例如您可能想要的韩文设置(以及 Apple 未来默认添加的任何其他值)。我会在 ObjC 中使用 label.lineBreakStrategy &= ~NSLineBreakStrategyPushOut;,在 Swift 中使用 label.lineBreakStrategy.remove(.pushOut)
【解决方案4】:

这不是一个真正的答案,但我想添加一个说明,说明这是一个普遍问题,与 & 符号完全无关。

这两个 UILabel 具有相同的宽度约束,并且文本几乎相同。但第二个有我期望的自动换行。第一个是不正确的,“about”可以清楚地留在第一行。

【讨论】:

  • 很好的例子。当试图将文本放置在某种聊天气泡或其他“容器”视图中时,这种类型的自动换行特别烦人,因为正如你所说,标签的宽度在两种情况下都是相同的,而实际上,在第一种情况下它应该窄得多。在所述容器视图中导致大量空白。
【解决方案5】:

似乎用不间断空格 (U+00A0) 替换 & 号之前的空格可以使 & 号保持在同一行。根据您为标签生成文本的方式,这可能不容易自动化(在某些情况下,您可能确实需要将 & 符号放在第二行)。

【讨论】:

    【解决方案6】:

    一个选项可能是使用 UITextView 代替——它似乎没有这种行为。如果将 NSTextContainer.lineFragmentPadding 设置为 0,将 textContainerInset 设置为 UIEdgeInsetsZero,并关闭所有滚动(scrollEnabled、反弹、滚动指示器等),它将类似于 UILabel 显示,但没有那么多的约束灵活性。它不是直接替代品,但在某些情况下是可以接受的。

    【讨论】:

    • 是的,但是我们怎样才能删除文本突出显示或选择呢?
    • 同时关闭 selectableeditable 属性。关闭userInteractionEnabled 也无妨。
    • 是的,在这种情况下我忘记了..是的,它可以做到..但是如果你想要链接或超文本,比如像 twitter 和 instagram 这样的标签标签 .. 突出显示不会被删除.. .
    • 无论如何你都不能点击 UILabel 中的链接(即使它们显示为蓝色),所以我不确定你会从 UILabel 中遗漏什么。使用 UITextView,您可能会保留用户交互(即使 selectable 为 false)并在委托方法中获取链接。
    【解决方案7】:

    有点小技巧,但您可以在字符串末尾添加一些零宽度空格以恢复旧行为,而不会影响字符串的布局,否则您会从正常空格中获得:

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

    【讨论】:

      【解决方案8】:

      作为一种简单(hacky)的解决方法,您通常可以通过在文本末尾添加空格来使用 UILabel 获得正确的行为。使用您的示例:

      包装新的(不受欢迎的)方式:
      "oneText & two."

      旧方式换行:
      "oneText & two. "(注意字符串末尾的 2 个额外空格)

      明显的缺点是,如果这些额外的空格自己被强制换行,但对于像标题这样简单的东西,这通常就足够了。

      【讨论】:

      • 就我而言,我需要添加 6 个额外的空格。少一点也没用……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-29
      • 2018-02-28
      • 1970-01-01
      • 2015-09-12
      • 2010-11-10
      • 1970-01-01
      相关资源
      最近更新 更多