问题
I am getting issues in autorotation of a UIView which is nothing but a red line of width 4 and height half of superview's height in landscape mode, and in portrait mode the height is 4 points and width is half of superview width. You can see the issue in the gif. As I rotate from landscape to portrait, the effect of autorotation is not smooth and with distortions.
Here is the code. What am I doing wrong?
private var myView:UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width/2, height: 4))
myView.backgroundColor = UIColor.red
view.addSubview(myView)
myView.center = CGPoint(x: view.bounds.width/2, y: view.bounds.height/2)
}
private func layoutMyView() {
let orientation = UIApplication.shared.statusBarOrientation
if orientation == .landscapeLeft || orientation == .landscapeRight {
myView.frame = CGRect(x: 0, y: 0, width: view.bounds.width/2, height: 4)
} else {
myView.frame = CGRect(x: 0, y: 0, width: 4, height: view.bounds.height/2)
}
myView.center = CGPoint(x: view.bounds.width/2, y: view.bounds.height/2)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
let orientation = UIApplication.shared.statusBarOrientation
NSLog("View will transition to \(size), \(orientation.rawValue)")
if size.width < size.height {
NSLog("Portrait mode")
} else {
NSLog("Landscape mode")
}
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { [unowned self] (_) in
let orient = UIApplication.shared.statusBarOrientation
self.layoutMyView()
}, completion: { [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in
let orient = UIApplication.shared.statusBarOrientation
self.layoutMyView()
NSLog("rotation completed to \(orient.rawValue), \(self.myView.frame)")
})
}
回答1:
There are a few potential options:
In
animate(alongsideTransition:completion:)
, do a keyframe animation to set mid animation point so you don’t end up with that curious boxy feel mid animation. E.g. this shrink it down to a 4x4 boxoverride func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) let origin = CGPoint(x: (view.bounds.midX + view.bounds.midY) / 2 - 2, y: (view.bounds.midX + view.bounds.midY) / 2 - 2) coordinator.animate(alongsideTransition: { _ in UIView.animateKeyframes(withDuration: coordinator.transitionDuration, delay: 0, animations: { UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) { self.myView.frame = CGRect(origin: origin, size: CGSize(width: 4, height: 4)) } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) { self.layoutMyView() } }) }) }
There are many possible variations on this theme. This still animates the view, but gives it a more “deliberate” sort of vibe and doesn’t lose the “line” feel of it.
Rather than rendering a “line” with
UIView
, use CAShapeLayer and update its path.You could run a CADisplayLink while transition is in progress, and then update the frame to whatever you want as the animation progresses.
Instead of animating the
frame
, you could animate thetransform
of this view, possibly rotating it in the opposite direction that the view is rotating.
来源:https://stackoverflow.com/questions/54389933/uiview-autorotation-issue