我已经开始使用Swift在Xcode中创建自定义视图。我决定使用http://www.thinkandbuild.it/building-a-custom-and-designabl-control-in-swift/中显示的方法,允许我在Interface Builder中设置控件的属性。
更新:我继续构建视图,在自定义视图的子视图中排列标签,并将子视图与视图对齐。我最终在两个级别上都使用了自动布局和约束,并设法通过这种方式解决了宽度问题。我相应地更新了下面的代码。
还存在两个问题:
txtButton.setTranslatesAutoresizingMaskIntoConstraints(false)
并设置txtButton子视图的约束=> 子视图的边框和背景消失。自定义视图类:
import UIKit
@IBDesignable public class TextButtonView: UIView {
@IBInspectable var borderColor: UIColor = UIColor.clearColor()
@IBInspectable var borderWidth: CGFloat = 0
@IBInspectable var cornerRadius: CGFloat = 0
@IBInspectable var viewBackgroundColor: UIColor = UIColor.clearColor()
@IBInspectable var mainText: String = ""
@IBInspectable var mainTextSize: CGFloat = 15.0
@IBInspectable var mainTextColor: UIColor = UIColor.blackColor()
@IBInspectable var secText: String = ""
@IBInspectable var secTextSize: CGFloat = 15.0
@IBInspectable var secTextColor: UIColor = UIColor.blackColor()
@IBInspectable var horizMargin: CGFloat = 5.0
@IBInspectable var secHorizOffset: CGFloat = 0.0
@IBInspectable var verticalMargin: CGFloat = 3.0
@IBInspectable var lineSpacing: CGFloat = 10.0
var txtButton: UIControl!
var buttonHeight: CGFloat = 0.0
#if TARGET_INTERFACE_BUILDER
override func willMoveToSuperview(newSuperview: UIView?) {
// Build the TextButton.
txtButton = TextButton(
borderColor: self.borderColor,
borderWidth: self.borderWidth,
cornerRadius: self.cornerRadius,
viewBackgroundColor: self.viewBackgroundColor,
mainText: self.mainText,
mainTextSize: self.mainTextSize,
mainTextColor: self.mainTextColor,
secText: self.secText,
secTextSize: self.secTextSize,
secTextColor: self.secTextColor,
horizMargin: self.horizMargin,
secHorizOffset: self.secHorizOffset,
verticalMargin: self.verticalMargin,
lineSpacing: self.lineSpacing,
frame: self.bounds)
// Add the TextButton as subview of this view
self.addSubview(txtButton)
// Remember height for setting intrinsic content size.
buttonHeight = txtButton.frame.size.height
// Set remaining attributes for the container view.
self.backgroundColor = UIColor.clearColor()
// Setting constraints for the subview.
txtButton.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addConstraint(NSLayoutConstraint(item: txtButton, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: txtButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: txtButton, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0))
}
#else
override public func awakeFromNib() {
super.awakeFromNib()
// Build the TextButton.
txtButton = TextButton(
borderColor: self.borderColor,
borderWidth: self.borderWidth,
cornerRadius: self.cornerRadius,
viewBackgroundColor: self.viewBackgroundColor,
mainText: self.mainText,
mainTextSize: self.mainTextSize,
mainTextColor: self.mainTextColor,
secText: self.secText,
secTextSize: self.secTextSize,
secTextColor: self.secTextColor,
horizMargin: self.horizMargin,
secHorizOffset: self.secHorizOffset,
verticalMargin: self.verticalMargin,
lineSpacing: self.lineSpacing,
frame: self.bounds)
// Add the TextButton as subview of this view.
self.addSubview(txtButton)
// Remember height for setting intrinsic content size.
buttonHeight = txtButton.frame.size.height
// Set remaining attributes for the container view.
self.backgroundColor = UIColor.clearColor()
// Setting constraints for the subview.
txtButton.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addConstraint(NSLayoutConstraint(item: txtButton, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: txtButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: txtButton, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0))
}
#endif
override public func intrinsicContentSize() -> CGSize {
return CGSize(width: 250, height: buttonHeight)
}
}
控制:
import UIKit
class TextButton: UIControl {
// Designable properties and default values.
var borderColor: UIColor?
var borderWidth: CGFloat?
var cornerRadius: CGFloat?
var viewBackgroundColor: UIColor?
var mainText: String?
var mainTextSize: CGFloat?
var mainTextColor: UIColor?
var secText: String?
var secTextSize: CGFloat?
var secTextColor: UIColor?
var horizMargin: CGFloat?
var secHorizOffset: CGFloat?
var verticalMargin: CGFloat?
var lineSpacing: CGFloat?
convenience init(
borderColor: UIColor,
borderWidth: CGFloat,
cornerRadius: CGFloat,
viewBackgroundColor: UIColor,
mainText: String,
mainTextSize: CGFloat,
mainTextColor: UIColor,
secText: String,
secTextSize: CGFloat,
secTextColor: UIColor,
horizMargin: CGFloat,
secHorizOffset: CGFloat,
verticalMargin: CGFloat,
lineSpacing: CGFloat,
frame: CGRect) {
self.init(frame: frame)
self.mainText = mainText
self.mainTextSize = mainTextSize
// Button margins.
self.horizMargin = horizMargin
self.verticalMargin = verticalMargin
self.secHorizOffset = secHorizOffset
self.lineSpacing = lineSpacing
// Define the Fonts
let mainFont = UIFont(name: "Helvetica Neue", size: mainTextSize)
let secFont = UIFont(name: "Helvetica Neue", size: secTextSize)
// Create main label.
let mainLabel: UILabel = UILabel()
mainLabel.backgroundColor = UIColor.clearColor()
mainLabel.textColor = mainTextColor
mainLabel.textAlignment = .Left
mainLabel.font = mainFont
mainLabel.text = mainText
// Calculate the main label's height.
var mainLabelDummy: UILabel = mainLabel
mainLabelDummy.sizeToFit()
var mainLabelHeight: CGFloat = mainLabelDummy.frame.size.height
// Create secondary label.
let secLabel: UILabel = UILabel()
secLabel.backgroundColor = UIColor.clearColor()
secLabel.textColor = secTextColor
secLabel.textAlignment = .Left
secLabel.font = secFont
secLabel.text = secText
// Calculate the secondary label's height.
var secLabelDummy: UILabel = secLabel
secLabelDummy.sizeToFit()
var secLabelHeight: CGFloat = secLabelDummy.frame.size.height
// Add labels to view.
addSubview(mainLabel)
addSubview(secLabel)
// Set constraints for labels.
mainLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
secLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addConstraint(NSLayoutConstraint(item: mainLabel, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: horizMargin))
self.addConstraint(NSLayoutConstraint(item: mainLabel, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0 - horizMargin))
self.addConstraint(NSLayoutConstraint(item: mainLabel, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: verticalMargin))
self.addConstraint(NSLayoutConstraint(item: secLabel, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: horizMargin + secHorizOffset))
self.addConstraint(NSLayoutConstraint(item: secLabel, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0 - horizMargin))
self.addConstraint(NSLayoutConstraint(item: secLabel, attribute: .Top, relatedBy: .Equal, toItem: mainLabel, attribute: .Bottom, multiplier: 1, constant: lineSpacing))
// Adjust frame to match content.
self.frame.size.height =
2 * verticalMargin
+ 2 * borderWidth
+ lineSpacing
+ mainLabelHeight
+ secLabelHeight
// Set remaining view properties.
self.layer.borderColor = borderColor.CGColor
self.layer.borderWidth = borderWidth
self.layer.cornerRadius = cornerRadius
self.backgroundColor = viewBackgroundColor
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
答案 0 :(得分:0)
进一步阅读后,我提出了以下解决方案,通过删除子视图进行简化:
import UIKit
@IBDesignable class TextButtonView: UIControl {
// Properties accessible in Interface Builder.
@IBInspectable var borderColor: UIColor = UIColor.clearColor() {didSet { updateUI() }}
@IBInspectable var borderWidth: CGFloat = 0 {didSet { updateUI() }}
@IBInspectable var cornerRadius: CGFloat = 0 {didSet { updateUI() }}
@IBInspectable var backgrColor: UIColor = UIColor.clearColor() {didSet { updateUI() }}
@IBInspectable var mainText: String = "" {didSet { updateUI() }}
@IBInspectable var mainTextSize: CGFloat = 20.0 {didSet { updateUI() }}
@IBInspectable var mainTextColor: UIColor = UIColor.blackColor() {didSet { updateUI() }}
@IBInspectable var secText: String = "" {didSet { updateUI() }}
@IBInspectable var secTextSize: CGFloat = 12.0 {didSet { updateUI() }}
@IBInspectable var secTextColor: UIColor = UIColor.blackColor() {didSet { updateUI() }}
@IBInspectable var horizMargin: CGFloat = 0.0 {didSet { updateUI() }}
@IBInspectable var secHorizOffset: CGFloat = 0.0 {didSet { updateUI() }}
@IBInspectable var verticalMargin: CGFloat = 0.0 {didSet { updateUI() }}
@IBInspectable var lineSpacing: CGFloat = 0.0 {didSet { updateUI() }}
var mainLabel: UILabel!
var secLabel: UILabel!
var textButtonHeight: CGFloat = 0.0
var fontName: String = "Helvetica Neue"
required init(coder: NSCoder) {
super.init(coder:coder)
setupUI()
}
override init(frame: CGRect) {
super.init(frame:frame)
setupUI()
}
func setupUI() {
// Set up static properties.
mainLabel = UILabel()
mainLabel.backgroundColor = UIColor.clearColor()
mainLabel.textAlignment = .Left
secLabel = UILabel()
secLabel.backgroundColor = UIColor.clearColor()
secLabel.textAlignment = .Left
// Add labels to view.
addSubview(mainLabel)
addSubview(secLabel)
// Update variable properties.
updateUI()
}
func updateUI() {
// Set borders and background.
self.layer.borderColor = borderColor.CGColor
self.layer.borderWidth = borderWidth
self.layer.cornerRadius = cornerRadius
self.layer.backgroundColor = backgrColor.CGColor
// Update main label.
mainLabel.textColor = mainTextColor
mainLabel.font = UIFont(name: fontName, size: mainTextSize)
mainLabel.text = mainText
// Update secondary label.
secLabel.textColor = secTextColor
secLabel.font = UIFont(name: fontName, size: secTextSize)
secLabel.text = secText
// Calculate view's height.
var mainLabelCopy: UILabel = mainLabel
mainLabelCopy.sizeToFit()
var mainLabelHeight: CGFloat = mainLabelCopy.frame.size.height
var secLabelCopy: UILabel = secLabel
secLabelCopy.sizeToFit()
var secLabelHeight: CGFloat = secLabelCopy.frame.size.height
textButtonHeight =
2 * verticalMargin
+ 2 * borderWidth
+ lineSpacing
+ mainLabelHeight
+ secLabelHeight
setNeedsUpdateConstraints()
}
override func updateConstraints() {
// Set constraints for labels.
setTranslatesAutoresizingMaskIntoConstraints(false)
mainLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
secLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
removeConstraints(constraints())
self.addConstraint(NSLayoutConstraint(item: mainLabel, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: horizMargin))
self.addConstraint(NSLayoutConstraint(item: mainLabel, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0 - horizMargin))
self.addConstraint(NSLayoutConstraint(item: mainLabel, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: verticalMargin))
self.addConstraint(NSLayoutConstraint(item: secLabel, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1, constant: horizMargin + secHorizOffset))
self.addConstraint(NSLayoutConstraint(item: secLabel, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0 - horizMargin))
self.addConstraint(NSLayoutConstraint(item: secLabel, attribute: .Top, relatedBy: .Equal, toItem: mainLabel, attribute: .Bottom, multiplier: 1, constant: lineSpacing))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: textButtonHeight))
super.updateConstraints()
}
}
在运行时,现在按预期工作。
在Interface Builder中,它仍会抛出一些关于错误放置的视图的警告,这些警告实际上没有意义。报告的实际坐标似乎不正确,IB中的手动和自动校正都没有修复它。
然而,这允许我继续,所以我将其作为建议的答案发布。
答案 1 :(得分:0)
我遇到了与此类似的问题,以编程方式创建约束并且子视图根本不显示。我解决这个问题的方法是将高度和宽度设置为约束。我很确定这会解决您遇到的第一个问题。