即使有足够的空间可用于单词,UILabel 自动换行功能也会留下空间
Posted
技术标签:
【中文标题】即使有足够的空间可用于单词,UILabel 自动换行功能也会留下空间【英文标题】:UILabel word wrap feature leaving space even when sufficient space available for the word 【发布时间】:2021-04-11 04:07:34 【问题描述】:这个问题甚至出现在故事板中。
UILabel 具有以下属性:
numberOfLines = 0 lineBreakMode = .byWordWrapping 约束:领先和落后 26 点到 superview;垂直居中。 自定义字体:中等 17 磅。如您所见,第四个单词无法放入第一行,因此会出现布局错误的问题。如果我删除最后一个单词,则句子完全适合一行或说出第四个单词。如果在它之后添加一个单词会将它们都移动到下一行,这会留下很多空间。它应该尝试在一行中尽可能不中断或连字符来适应单词。但是很明显,即使单词可以容纳,也会产生空白。
您可以在新项目中重新创建它并观察问题。
【问题讨论】:
使用label.sizeToFit()
。它可能会有所帮助。
还是没有帮助...
Apple 设计了自动换行算法来避免“寡妇”——即避免将单个单词作为段落的最后一行。在谷歌上快速搜索UILabel widows
,你会发现很多讨论解释了它发生的原因,以及尝试解决它的各种方法。
嗨@DonMag 感谢您为我指明正确的方向。但是它与自动换行没有任何关系,因为它在所有换行模式下都表现出相同的行为。
如果你将它设置为Character Wrap
,它的行为会有所不同,但当然这会在单词中间中断,我确定你不想要。 Apple 在 ios 10 或 11 左右改变了这一点(我记得)。如果它适用于您的目的,您可以使用不可滚动、不可编辑的 UITextView
代替您的 UILabel
-- 文本视图不避免寡妇和孤儿(我应该说“孤儿”开头,有区别)。
【参考方案1】:
您可能想尝试一下...
子类UITextView
,禁用滚动、编辑和选择...将textContainerInset = UIEdgeInsets.zero
和textContainer.lineFragmentPadding = 0
设置为零。
结果:
代码(@IBDesignable
所以我们可以在 IB / Storyboard 中看到它):
@IBDesignable
class TextViewLabel: UITextView
override init(frame: CGRect, textContainer: NSTextContainer?)
super.init(frame: frame, textContainer: textContainer)
commonInit()
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
commonInit()
func commonInit() -> Void
isScrollEnabled = false
isEditable = false
isSelectable = false
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
【讨论】:
非常感谢!! :) @kelalaka - 哎呀......已修复。【参考方案2】:此代码可用于固定宽度的标签,它会克服这一点, 也可以得到标签的高度
private static func calculateLabelProperties() -> (String, CGFloat)
let titleString = "Your string here"
let wordArray = titleString.components(separatedBy: " ")
var lineCount = 1//first line denoted by 1
var tempWidth:CGFloat = 0
var title = ""
for (index,element) in wordArray.enumerated()
let width = calculateFontSize(title: element + " ", fontName: "your font name", fontSize: 17).width
tempWidth = tempWidth + width
//get the nextelement
var nextElement = ""
if wordArray.count > index + 1
nextElement = wordArray[index + 1]
let nextElementWidth = calculateFontSize(title: nextElement, fontName: "your font name", fontSize: 17).width
if tempWidth + nextElementWidth > 410 //410 is labelwidth
tempWidth = 0
lineCount += 1
title = "\(title)\(element)\n"
else
title = "\(title)\(element) "
return (title, CGFloat(lineCount * 20))//20 is label sigle line height
此代码计算字体大小
func calculateFontSize(title: String, fontName: String, fontSize: CGFloat) -> (width: CGFloat, height: CGFloat)
let font = UIFont(name: fontName, size: fontSize)
return (title.size(OfFont: font!).width, title.size(OfFont: font!).height)
获取字体大小
extension String
func size(OfFont font: UIFont) -> CGSize
return (self as NSString).size(withAttributes: [NSAttributedString.Key.font: font])
【讨论】:
以上是关于即使有足够的空间可用于单词,UILabel 自动换行功能也会留下空间的主要内容,如果未能解决你的问题,请参考以下文章
如何在 iOS 的 UILabel/UITextView 中处理多种屏幕尺寸的中文自动换行?