我有一个 UILabel 位于 UICollectionViewCell 内。 UILabel 是多行,并且根据提供的文本可能具有不同的大小。该单元格位于具有简单 UICollectionViewCompositionalLayout 的集合视图中。
标签大小调整正确,但标签中的文本有时绘制不正确,文本实际上并非从顶部开始,这会导致标签被切断。
如果您看一下上面的屏幕截图,您可以看到上面写着“第五个人做了某事”,但被切断了。您可以看到它实际上并不是从顶部开始绘制,与其他单元格不同(我在 UILabel 周围放置了轮廓)。标签的尺寸实际上是正确的,只是文本被关闭了。
根据我使用的模拟器,这种截止可能会发生在文本较长的单元格或文本较短的单元格中。唯一的共同点是,当我使用统一大小的文本时,我看不到这种情况发生,但是当我使用不同大小的文本时,它就会发生。
我已经尝试了几乎所有我能想到的layoutSubviews()、sizeToFit()、setLayoutIfNeeded()配置。我尝试过使用 UITextView ,有趣的是它也会被切断。
我做了一个最小的可重现示例,但单元格的代码在这里:
class NotificationsCell: UICollectionViewCell {
// Structure
var mainView = UIStackView(.vertical)
var mainStack = UIStackView(.horizontal, spacing: 5)
// Left side
var leftArea = UIView()
var imageView = ImageBall(fontSize: 16)
// Right Side
var rightArea = UIView()
var rightStack = UIStackView(.vertical, spacing: 5)
var titleLabel = UILabel()
// Data
var data: UserNotification? {
didSet {
self.updateContent()
}
}
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
//print("RecipeCell - init")
setUpViews()
setUpUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
//print("RecipeCell - init")
setUpViews()
setUpUI()
}
func setUpViews() {
// Main
self.constrain(mainView, using: .edges, padding: 2, debugName: "mainView -> cell")
mainView.add([mainStack, Spacer(1, .vertical, color: .grayColor)])
mainStack.add([leftArea, rightArea])
// Right
rightArea.constrain(rightStack, using: .scale, widthScale: 0.9, heightScale: 0.8)
rightStack.add([titleLabel])
// Left
leftArea.constrain(imageView, using: .scale, widthScale: 0.9, except: [.height, .centerY])
imageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
imageView.topAnchor.constraint(equalTo: rightStack.topAnchor).isActive = true
}
func setUpUI() {
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.textAlignment = .left
titleLabel.numberOfLines = -1
titleLabel.layer.borderWidth = 1
}
func updateContent() {
guard let update = self.data else {
print("NotificationsCell - Update Content - No data")
return
}
self.titleLabel.attributedText = update.generateNotificationString()
self.imageView.set(color: .lightBluePrimary)
self.imageView.set(labelText: "DA")
self.layoutSubviews()
}
override func prepareForReuse() {
titleLabel.text = ""
}
}
视图/集合视图的代码在这里:
class NotificationsView: UIView {
// View Controller
weak var viewController: NotificationsViewController!
// Main Stack
var mainStack = UIStackView()
// Title View
var titleArea = UIStackView(.horizontal)
var titleTextView: UITextView = {
let textView = UITextView()
textView.textColor = .orangeColor
textView.font = .systemFont(ofSize: 40, weight: .bold)
textView.isScrollEnabled = false
textView.isEditable = false
return textView
}()
// Body
var bodyView = UIStackView(.vertical)
// Collection View
var collectionView: UICollectionView?
var collectionViewLayout: UICollectionViewLayout?
init() {
super.init(frame: .zero)
setUpViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: Setup
extension NotificationsView {
private func setUpViews() {
self.backgroundColor = .white
// Mainstack
constrain(mainStack, using: .edges, padding: 15, safeAreaLayout: true, debugName: "NotificationsView - mainStack")
mainStack.constrain(titleArea, using: .edges, except: [.bottom])
mainStack.constrain(bodyView, using: .edges, except: [.top])
// Title Area
titleArea.bottomAnchor.constraint(equalTo: bodyView.topAnchor).isActive = true
titleArea.add([titleTextView, UIView()])
titleTextView.text = "Notifications"
// Body View
setUpCollectionView()
bodyView.constrain(collectionView!, using: .edges)
}
// Collection View
private func setUpCollectionView() {
self.collectionViewLayout = createCollectionViewLayout()
self.collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout!)
collectionView!.register(NotificationsCell.self, forCellWithReuseIdentifier: String(describing: NotificationsCell.self))
}
private func createCollectionViewLayout() -> UICollectionViewLayout {
let padding: CGFloat = 0
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(50))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: itemSize,
subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 0
section.contentInsets = .init(top: 0, leading: 15, bottom: padding, trailing: 15)
return UICollectionViewCompositionalLayout(section: section)
}
}
如果您确实查看了 MRP,请尝试在 iPhone SE 第 3 代模拟器中运行它以进行复制。您可以尝试在NotificationManager中调整通知的长度。 MRP 在这里:https://drive.google.com/file/d/1GokqMkh-cTyN1nBxmlnyJqc_OKl48SGL/view?usp=sharing
这是单元格自动布局的一个错误。要解决此问题,请实现
layoutSubviews
,并在覆盖中调用 super
后,将标签的 preferredMaxLayoutWidth
设置为其自己的 bounds.width
。
这非常重要且普遍需要,因此我在 UILabel 上进行了扩展:
extension UILabel {
func adjustWrapWidthToBoundsWidth() {
if text != nil {
preferredMaxLayoutWidth = bounds.width
}
}
}