UIView填充父视图的剩余空间

时间:2015-08-05 18:21:11

标签: ios swift autolayout

我的观点有2个子视图。 UITextView UIView 。视图是动态的(以编程方式)创建的。

使用AutoLayout。我想

  • UITextView增长到文本的高度
  • UIView填充父母的剩余空间

(见附件)

我怎样才能在swift中以编程方式执行此操作?

enter image description here

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

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

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