我的观点有2个子视图。 UITextView 和 UIView 。视图是动态的(以编程方式)创建的。
使用AutoLayout。我想
(见附件)
我怎样才能在swift中以编程方式执行此操作?
答案 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)
}
结果应该是这样的:
答案 1 :(得分:0)
1)在UIView
上设置约束,以保持UIView的顶部与UITextview底部之间的距离为零。
2)在UITextView
上添加高度约束。为UITextview的高度约束创建IBOutlet
。
3)现在在代码中更改UITextview高度约束的constant
属性