如何在堆栈视图中动态调整文本视图的大小

Posted

技术标签:

【中文标题】如何在堆栈视图中动态调整文本视图的大小【英文标题】:How to dynamically resize text view inside a stack view 【发布时间】:2021-07-06 01:32:12 【问题描述】:

我正在尝试在堆栈视图中显示动态大小的UITextView,但文本视图未调整到内容的大小。

首先我有安排好的子视图:

class InfoView: UIView 
    private var title: String!
    private var detail: String!
    private var titleLabel: UILabel!
    private var detailTextView: UITextView!
    
    init(infoModel: InfoModel) 
        self.title = infoModel.title
        self.detail = infoModel.detail
        super.init(frame: .zero)
        
        configure()
        setConstraint()
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    private func configure() 
        titleLabel = UILabel()
        titleLabel.text = title
        titleLabel.font = .rounded(ofSize: titleLabel.font.pointSize, weight: .bold)
        titleLabel.textColor = .lightGray
        titleLabel.sizeToFit()
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(titleLabel)
        
        detailTextView = UITextView()
        detailTextView.sizeToFit()
        detailTextView.text = detail
        detailTextView.font = UIFont.systemFont(ofSize: 19)
        detailTextView.isEditable = false
        detailTextView.textColor = .lightGray
        detailTextView.isUserInteractionEnabled = false
        detailTextView.isScrollEnabled = false
        detailTextView.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(detailTextView)
    
    
    private func setConstraint() 
        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: self.topAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5),
            titleLabel.heightAnchor.constraint(equalToConstant: 40),
            
            detailTextView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor),
            detailTextView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            detailTextView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            detailTextView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        ])
    

然后我在视图控制器中实现堆栈视图:

class MyViewController: UIViewController 
    var infoModelArr: [InfoModel]!
    var stackView: UIStackView!
    var scrollView: UIScrollView!
    
    init(infoModelArr: [InfoModel]) 
        self.infoModelArr = infoModelArr
        super.init(nibName: nil, bundle: nil)
    
    
    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    override func viewDidLoad() 
        super.viewDidLoad()
        var infoViewArr = [InfoView]()
        for infoModel in infoModelArr 
            let infoView = InfoView(infoModel: infoModel)
            infoViewArr.append(infoView)
        
        
        stackView = UIStackView(arrangedSubviews: infoViewArr)
        stackView.axis = .vertical
        stackView.spacing = 10
        stackView.distribution = .fillProportionally
        stackView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(stackView)
        
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
            stackView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
        ])
    

    override func viewDidLayoutSubviews() 
        super.viewDidLayoutSubviews()
        scrollView.contentSize = stackView.bounds.size
    

最后,我将视图控制器称为:

let myVC = MyViewController(infoModelArr: [InfoModel(title: "title", detail: "detail"), InfoModel(title: "title", detail: "detail")])
self.present(myVC, animated: true, completion: nil)

值得注意的是,如果我用单个排列的子视图实例化堆栈视图,堆栈视图的高度似乎是动态调整的,但是一旦引入 2 个或更多子视图,高度就不会反映内容.

当我尝试设置 InfoView 的内在大小时,

override func layoutSubviews() 
    super.layoutSubviews()
    height = titleLabel.bounds.height + detailTextView.bounds.height


var height: CGFloat! = 200 
    didSet 
        self.invalidateIntrinsicContentSize()
    


override var intrinsicContentSize: CGSize 
    let originalSize = super.intrinsicContentSize
    return CGSize(width: originalSize.width, height: height)

detailTextView.bounds.height 返回 0。

【问题讨论】:

你想重塑UITableView吗?您似乎没有正确使用UIScrollView(您甚至从未初始化它?)。 fillProportionally 在这里似乎也不合适。应该有一些约束被打破,对吧?您应该在问题中包含冲突的约束。我认为fill 更合适,但你为什么不首先使用UITableView @Sweeper 哎呀,缺少UIScrollView 是我在复制问题时的一个错误。 fill 似乎在起作用,所以如果你想发布答案,我会标记它。我使用UIStackView,因为我将只使用 1 - 3 个项目,但我肯定会考虑该选项。 【参考方案1】:

fillProportionally 分布尝试根据排列的子视图的固有内容大小缩放其高度,作为堆栈视图高度的比例。例如如果堆栈视图的高度为 120,排列的子视图 A 的固有高度为 10,排列的子视图 B 的固有高度为 20,则 A 和 B 在堆栈视图中的高度分别为 40 和 80。

您的堆栈视图没有定义的高度,因此fillProportionally 在这里没有多大意义。

相反,fill 的分布应该可以完成这项工作:

stackView.distribution = .fill

(作为实验,您可以尝试在堆栈视图中添加高度约束,您将看到fillProportionally 的工作原理)

【讨论】:

以上是关于如何在堆栈视图中动态调整文本视图的大小的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:动态设置图像的大小

如何在动态类型的 UIContentSizeCategoryDidChangeNotification 之后调整视图大小

动态宽度大小以适应堆栈视图中的控件

当堆栈视图调整大小时,如何让 NSButton 与 NSStackView 分离?

如何在 Xcode 7 中使用对象库的堆栈视图

动态调整视图大小 osx