UIView填充父视图剩余空间

4

我的视图有两个子视图。一个是UITextView,另一个是UIView。这些视图是动态(通过编程方式)创建的。

使用AutoLayout。我想要:

  • UITextView根据文本内容自动增长高度
  • UIView填充父级剩余空间

(见附件)

我该如何在Swift中通过编程实现这一点?

enter image description here


1
你总是可以从nib文件中实现这个功能,而且更容易。不管怎样,我相信关键在于“以编程方式”?所以,你想要在代码中从头开始构建完整的视图吗? - Hugo Alonso
是的,我将从头开始构建视图。 - Prakash Raman
1
好的,我正在努力解决方案。 - Hugo Alonso
非常感谢您:) - Prakash Raman
好的,我添加了一个解决方案,对于延迟我很抱歉,但同时有其他事情要做。 - Hugo Alonso
3个回答

1
对于Swift 4:

让视图填充剩余屏幕空间:

yourView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
yourView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

yourView附加到其父视图的顶部和底部锚点,使其能够在高度更改时增长/缩小。

1

1) 在UIView上设置约束,使UIView的顶部与UITextview的底部保持零距离。

2) 在UITextView上添加高度约束。为UITextview的高度约束创建一个IBOutlet

3) 现在在您的代码中更改UITextview的高度约束的constant属性。


1

好的,这段代码有点长,也许还有很大的改进空间。但是这已经足够了。

AdjustableView.swift

import UIKit
import Foundation

class AdjustableView: UIView, UITextViewDelegate {
 var viewTop : UITextView!
 var viewBottom : UIView!
 weak var heightConstraint : NSLayoutConstraint!
 var countFinalLines : Int?

override init(frame: CGRect) {
    super.init(frame: frame)
    buildBothViews(frame)
}

private func buildBothViews(frame: CGRect) {
    viewTop = UITextView()
    viewBottom = UIView()

    //This is just for testing and checking that it does exactly what I want
    viewTop.backgroundColor = UIColor.orangeColor()
    viewBottom.backgroundColor = UIColor.greenColor()

    setConstraints()
    initTextView()
}

/**
Sets the settings for the UITextView
*/
func initTextView(){
    let insets = UIEdgeInsets(top: 20, left: 10, bottom: 20, right: 10)
    viewTop.contentInset = insets
    viewTop.delegate = self
    viewTop.bounces = false
    viewTop.scrollEnabled = false
    viewTop.textAlignment = NSTextAlignment.Center
}

/**
This will arrange the views
*/
func setConstraints(){
     //I'm using this proportion as my initial height for the UITextView, you can set it for any other.
    //My UITextView will not be allowed to go less tall than this height
    let initialProportion = frame.height/8

    let leftConstraint1 = NSLayoutConstraint(
        item: viewBottom, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Left, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: self, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Left, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )
    let leftConstraint2 = NSLayoutConstraint(
        item: viewTop, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Left, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: self, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Left, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )
    let rightConstraint1 = NSLayoutConstraint(
        item: viewBottom, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Right, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: self, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Right, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )
    let rightConstraint2 = NSLayoutConstraint(
        item: viewTop, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Right, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: self, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Right, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )


    let topViewHeightConstraint = NSLayoutConstraint(
        item: viewTop, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Height, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.GreaterThanOrEqual, //-- how we want to relate THIS object to A DIFF object
        toItem: nil, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.NotAnAttribute, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: initialProportion
    )
    let topConstraint = NSLayoutConstraint(
        item: viewTop, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Top, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: self, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Top, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )
    let distanceConstraint = NSLayoutConstraint(
        item: viewTop, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Bottom, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: viewBottom, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Top, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )
    let bottomConstraint = NSLayoutConstraint(
        item: viewBottom, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Bottom, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: self, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.Bottom, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: 0
    )
    let bottomViewHeightConstraint = NSLayoutConstraint(
        item: viewBottom, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Height, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: nil, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.NotAnAttribute, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: frame.height - initialProportion
    )
    //This is the one I will need to modify
    heightConstraint = NSLayoutConstraint(
        item: viewTop, //-- the object that we want to constrain
        attribute: NSLayoutAttribute.Height, //-- the attribute of the object we want to constrain
        relatedBy: NSLayoutRelation.Equal, //-- how we want to relate THIS object to A DIFF object
        toItem: nil, //-- this is the different object we want to constrain to
        attribute: NSLayoutAttribute.NotAnAttribute, //-- the attribute of the different object
        multiplier: 1, //-- multiplier
        constant: initialProportion
    )

    bottomViewHeightConstraint.priority = 750
    topViewHeightConstraint.priority = 900

    var constraints = [NSLayoutConstraint]()
    //recopilate constraints created here
    constraints.append(heightConstraint)
    constraints.append(distanceConstraint)
    constraints.append(bottomConstraint)
    constraints.append(topConstraint)

    constraints.append(leftConstraint1)
    constraints.append(leftConstraint2)
    constraints.append(rightConstraint1)
    constraints.append(rightConstraint2)

    constraints.append(bottomViewHeightConstraint)
    constraints.append(topViewHeightConstraint)

    viewTop.setTranslatesAutoresizingMaskIntoConstraints(false)
    viewBottom.setTranslatesAutoresizingMaskIntoConstraints(false)
    //add them to the desired control

    self.addSubview(viewTop)
    self.addSubview(viewBottom)

    //Activates constrants
    NSLayoutConstraint.activateConstraints(constraints)
}
/**
We will listen for changes in the textView

:param: textView the top view
*/
func textViewDidChange(textView: UITextView){
    adjustHeightAccordingToText(textView)
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    if let theFrame = (aDecoder.decodeObjectForKey("frame") as? NSValue) {
        buildBothViews(theFrame.CGRectValue())
    }

}

//If my number of lines is changing for the modification occurring, then the height of this view should change
func adjustHeightAccordingToText(textView: UITextView){
    if countFinalLines == nil {
        countFinalLines = countLabelLines(textView)
    }else {
        let tentativeCountLines = countLabelLines(textView)
        if countFinalLines != tentativeCountLines {
            countFinalLines = tentativeCountLines
            let singleLineHeight = CGFloat(textView.font.lineHeight)
            heightConstraint?.constant = floor((CGFloat(countFinalLines! + 3) * singleLineHeight))
        }
    }
}
/**
Measure count of lines that will have a label after applying a font to it

:param: label the label to measure
:param: font  the font with the one to measure this label

:returns: number of lines
*/
private func countLabelLines(label:UITextView)->Int{
    if let text = label.text{
        // cast text to NSString so we can use sizeWithAttributes
        let myText = text as NSString

        //Set attributes
        let attributes = [NSFontAttributeName : label.font]

        //Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another
        let labelSize = myText.boundingRectWithSize(CGSizeMake(label.bounds.width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil)

        //Now we return the amount of lines using the ceil method
        let lines = ceil(CGFloat(labelSize.height) / label.font.lineHeight)
        return Int(lines)
    }
    return 0
}
}

"然后在您的UIViewController中"
override func viewDidLoad() {
    super.viewDidLoad()
    //Create an instance of AdjustableView and add it to view hierarchy 
    let adjustableView = AdjustableView(frame: view.frame)
    view.addSubview(adjustableView)
}

结果应该是这样的:

初始状态

Initial State

在插入一些文本后

After some Text Insertion


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接