UILabel 无法在 UICollectionViewCell 中正确绘制文本

问题描述 投票:0回答:1

我有一个 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

ios swift autolayout uilabel uicollectionviewcell
1个回答
0
投票

这是单元格自动布局的一个错误。要解决此问题,请实现

layoutSubviews
,并在覆盖中调用
super
后,将标签的
preferredMaxLayoutWidth
设置为其自己的
bounds.width

这非常重要且普遍需要,因此我在 UILabel 上进行了扩展:

extension UILabel {
    func adjustWrapWidthToBoundsWidth() {
        if text != nil {
            preferredMaxLayoutWidth = bounds.width
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.