我正在尝试校准 UIView,使其在旋转时保持在中心位置。这是由 my previous question 的最佳答案确定的问题。 .我已经根据 one answer 设计了代码建议使用 viewWillAppear
或 viewDidLayoutSubviews
而不是 viewDidLoad
。
因为我是 Swift 的新手,所以我不得不重新访问 Swift 教程实现自定义控件,其中描述了 how to make a subClass of UIView .我的代码可以使用以下三个函数中的任何一个绘制一个圆:viewWillAppear
、viewDidLayoutSubviews
或 viewDidLoad
。
然而,当我渲染代码时,随着屏幕旋转,圆圈并不总是保持在中心位置。以下是使用 viewDidLoad
或 viewWillAppear
发生的连续旋转当应用程序在纵向屏幕上启动时,问题会在第一次旋转后立即出现,无论是向左还是向右。如果以横向启动,如果没有尝试至少四次连续旋转,则可能会错过问题。
下面是使用 viewDidLayoutSubviews
发生的连续旋转,其中旋转偶尔会导致中心圆覆盖偏离中心的圆。 这可能会在多次旋转后发生,但必须至少完成四次旋转才能发现问题。
这是 CircleView
的代码 - 我试图创建 UIView 的子类
import UIKit
class CircleView: UIView {
let radius = CGFloat(200)
let x: CGFloat = 0
let y: CGFloat = 0
// MARK: Initialization
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
// The Bezier path that we made needs to be converted
// to a CGPath before it can be used on a layer.
shapeLayer.path = createBezierPath().cgPath
// apply other properties related to the path
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.lineWidth = 8.0
// add the new layer to our custom view
self.layer.addSublayer(shapeLayer)
}
func createBezierPath() -> UIBezierPath {
// create a new path
let path = UIBezierPath(arcCenter: CGPoint(x: x, y: y),
radius: radius,
startAngle: CGFloat(M_PI * -0.5),
endAngle:CGFloat(M_PI * 1.5),
clockwise: true)
path.fill()
path.stroke()
return path
}
}
这是 ViewController 的代码
import UIKit
class ViewController: UIViewController {
var circle: CircleView?
var x: CGFloat?
var y: CGFloat?
override func viewDidLoad() {
super.viewDidLoad()
let centre = centreCircle()
// create a new UIView and add it to the view controller
let circleView = CircleView()
circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0)
view.addSubview(circleView)
}
func centreCircle() -> CGPoint {
circle?.bounds = UIScreen.main.bounds
return CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY)
}
}
这是返回屏幕中心点的 UIScreen 扩展的代码
import UIKit
extension UIScreen {
var centre: CGPoint {
return CGPoint(x: bounds.midX, y: bounds.midY)
}
}
为了产生上述旋转,我将 viewDidLoad
函数替换为 viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let centre = centreCircle()
// create a new UIView and add it to the view controller
let circleView = CircleView()
circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0)
view.addSubview(circleView)
}
或viewDidLayoutSubviews
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let centre = centreCircle()
// create a new UIView and add it to the view controller
let circleView = CircleView()
circleView.frame = CGRect(x: centre.x, y: centre.y, width: 0, height: 0)
view.addSubview(circleView)
}
任何人都可以在我的代码中看到可能阻止旋转工作的问题吗?
最佳答案
首先, View 在 viewdidload 和 viewwillappear 中的布局不正确,并且您明确定义了带有值的框架,作为新手程序员,我发现这非常令人沮丧。尤其是在调整标签大小时,这仍然让我很恼火。因此,将您的 View 和主屏幕的 centerX 和 centerY 放在一起意味着您的 View 将在您旋转时停留在该点。
通过学习自动布局来解决这个问题。起初它很糟糕,但它最终会让你的生活更轻松。看看这个扩展中的方法。当我想将一个 View 居中到另一个 View 时,我会使用它
extension UIView {
func constrainAndCenter(in view: UIView, withRelativeHeight: CGFloat, withRelativeWidth: CGFloat) -> [NSLayoutConstraint] {
self.translatesAutoresizingMaskIntoConstraints = false
let x = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0)
let w = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: withRelativeWidth, constant: 0)
let h = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: view, attribute: .height, multiplier: withRelativeHeight, constant: 0)
let y = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)
return ([x,w,h,y])
}
}
// then in viewdidload or whereever
let circleView = CircleView()
let circleViewConstraints = circleView.constrainAndCenter(in: view,....)
view.addSubview(circleView)
NSLayoutConstraint.activate(circleViewConstraints)
这会将它固定在中间。您也可以在界面构建器中执行此操作。
关于ios - 为什么 UIView 旋转时不居中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40059009/