IBOutlet 初始化中的 UIView 框架中心不正确
UIView frame center in IBOutlet initialization is incorrect
我有一个应该在视图中心呈现的进度条,但由于自动布局而最终偏离中心。
class ProgressView: UIView {
private let progressLayer: CAShapeLayer = CAShapeLayer()
private var progressLabel: UILabel
required init?(coder aDecoder: NSCoder) {
progressLabel = UILabel()
super.init(coder: aDecoder)
createProgressLayer()
createLabel()
}
override init(frame: CGRect) {
progressLabel = UILabel()
super.init(frame: frame)
createProgressLayer()
createLabel()
}
private func createProgressLayer() {
let startAngle = CGFloat(3*M_PI_2)
let endAngle = CGFloat(M_PI * 2 + 3*M_PI_2)
let centerPoint = CGPointMake(CGRectGetWidth(bounds)/2, CGRectGetHeight(bounds)/2)
let gradientMaskLayer = gradientMask()
progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: CGRectGetWidth(frame)/2-8, startAngle:startAngle, endAngle:endAngle, clockwise: true).CGPath
progressLayer.backgroundColor = UIColor.clearColor().CGColor
progressLayer.fillColor = nil
progressLayer.strokeColor = UIColor.blackColor().CGColor
progressLayer.lineWidth = 4.0
progressLayer.strokeStart = 0.0
progressLayer.strokeEnd = 0.0
gradientMaskLayer.mask = progressLayer
layer.addSublayer(gradientMaskLayer)
}
func animateProgressView() {
progressLayer.strokeEnd = 0.0
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = CGFloat(0.0)
animation.toValue = CGFloat(1.0)
animation.duration = 2.0
animation.delegate = self
animation.removedOnCompletion = false
animation.additive = true
animation.fillMode = kCAFillModeForwards
progressLayer.addAnimation(animation, forKey: "strokeEnd")
}
}
这段代码调用如下:
class MainPageController: UIViewController {
@IBOutlet var progressView : ProgressView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
progressView.animateProgressView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
最后绘制的圆偏离了中心。如果我手动编辑圆心,右侧和底部的栏似乎被切断了。如果我关闭自动布局,它工作正常。我做错了什么?
故事板:
在 Interface Builder 中,将 Progress View 的内容模式更改为重绘,并覆盖 drawRect 并从那里调用 createProgressLayer。
感谢您发布情节提要中的约束,我现在知道是什么原因造成的了。
ProgessView 设置有两个约束,一个是保持正方形,另一个是使其高度为视图高度的 1/3。这意味着您在情节提要中看到的视图大小与设备中的视图大小不同。
init?(coder aDecoder: NSCoder)
在从故事板加载视图时调用。它在自动布局运行之前调用,因此您获得的 bounds
和 frame
的值基于情节提要中的大小,即 200x200。然后自动布局运行并确定 phone 的大小(看起来像 iPhone 6)应该是 222x222。根据您的屏幕截图,您的进度视图的右侧和底部似乎有大约 22 磅的额外 space。
您需要做的是在自动布局将您的视图设置为合适的大小后调整进度层的大小。最好的地方是在 layoutSubviews
中,从 createProgressLayer
中移动一些行
func layoutSubviews() {
let startAngle = CGFloat(3*M_PI_2)
let endAngle = CGFloat(M_PI * 2 + 3*M_PI_2)
let centerPoint = CGPointMake(bounds.width/2, bounds.height/2)
progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2-8, startAngle:startAngle, endAngle:endAngle, clockwise: true).CGPath
}
我有一个应该在视图中心呈现的进度条,但由于自动布局而最终偏离中心。
class ProgressView: UIView {
private let progressLayer: CAShapeLayer = CAShapeLayer()
private var progressLabel: UILabel
required init?(coder aDecoder: NSCoder) {
progressLabel = UILabel()
super.init(coder: aDecoder)
createProgressLayer()
createLabel()
}
override init(frame: CGRect) {
progressLabel = UILabel()
super.init(frame: frame)
createProgressLayer()
createLabel()
}
private func createProgressLayer() {
let startAngle = CGFloat(3*M_PI_2)
let endAngle = CGFloat(M_PI * 2 + 3*M_PI_2)
let centerPoint = CGPointMake(CGRectGetWidth(bounds)/2, CGRectGetHeight(bounds)/2)
let gradientMaskLayer = gradientMask()
progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: CGRectGetWidth(frame)/2-8, startAngle:startAngle, endAngle:endAngle, clockwise: true).CGPath
progressLayer.backgroundColor = UIColor.clearColor().CGColor
progressLayer.fillColor = nil
progressLayer.strokeColor = UIColor.blackColor().CGColor
progressLayer.lineWidth = 4.0
progressLayer.strokeStart = 0.0
progressLayer.strokeEnd = 0.0
gradientMaskLayer.mask = progressLayer
layer.addSublayer(gradientMaskLayer)
}
func animateProgressView() {
progressLayer.strokeEnd = 0.0
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = CGFloat(0.0)
animation.toValue = CGFloat(1.0)
animation.duration = 2.0
animation.delegate = self
animation.removedOnCompletion = false
animation.additive = true
animation.fillMode = kCAFillModeForwards
progressLayer.addAnimation(animation, forKey: "strokeEnd")
}
}
这段代码调用如下:
class MainPageController: UIViewController {
@IBOutlet var progressView : ProgressView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
progressView.animateProgressView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
最后绘制的圆偏离了中心。如果我手动编辑圆心,右侧和底部的栏似乎被切断了。如果我关闭自动布局,它工作正常。我做错了什么?
故事板:
在 Interface Builder 中,将 Progress View 的内容模式更改为重绘,并覆盖 drawRect 并从那里调用 createProgressLayer。
感谢您发布情节提要中的约束,我现在知道是什么原因造成的了。
ProgessView 设置有两个约束,一个是保持正方形,另一个是使其高度为视图高度的 1/3。这意味着您在情节提要中看到的视图大小与设备中的视图大小不同。
init?(coder aDecoder: NSCoder)
在从故事板加载视图时调用。它在自动布局运行之前调用,因此您获得的 bounds
和 frame
的值基于情节提要中的大小,即 200x200。然后自动布局运行并确定 phone 的大小(看起来像 iPhone 6)应该是 222x222。根据您的屏幕截图,您的进度视图的右侧和底部似乎有大约 22 磅的额外 space。
您需要做的是在自动布局将您的视图设置为合适的大小后调整进度层的大小。最好的地方是在 layoutSubviews
中,从 createProgressLayer
func layoutSubviews() {
let startAngle = CGFloat(3*M_PI_2)
let endAngle = CGFloat(M_PI * 2 + 3*M_PI_2)
let centerPoint = CGPointMake(bounds.width/2, bounds.height/2)
progressLayer.path = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2-8, startAngle:startAngle, endAngle:endAngle, clockwise: true).CGPath
}