让视图填充剩余屏幕空间:
yourView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
yourView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
1) 在UIView
上设置约束,使UIView的顶部与UITextview的底部保持零距离。
2) 在UITextView
上添加高度约束。为UITextview的高度约束创建一个IBOutlet
。
3) 现在在您的代码中更改UITextview的高度约束的constant
属性。
好的,这段代码有点长,也许还有很大的改进空间。但是这已经足够了。
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)
}