屏幕旋转及ipad的分屏操作均会引起页面size的变化,此时会自动触发一些系统的方法:
- viewWillLayoutSubviews()
- viewDidLayoutSubviews()
- viewWillTransitionToSize()
- viewWillTransition(to:with:)
这里主要用到的是viewWillTransition(to:with:)
苹果官文https://developer.apple.com/documentation/uikit/uicontentcontainer/1621466-viewwilltransitiontosize?language=occ对该函数的解释很清楚:
UIKit calls this method before changing the size of a presented view controller’s view. You can override this method in your own objects and use it to perform additional tasks related to the size change. For example, a container view controller might use this method to override the traits of its embedded child view controllers. Use the provided coordinator object to animate any changes you make.
If you override this method in your custom view controllers, always call super at some point in your implementation so that UIKit can forward the size change message appropriately. View controllers forward the size change message to their views and child view controllers. Presentation controllers forward the size change to their presented view controller.
Parameters
size:
The new size for the container’s view.
coordinator:
The transition coordinator object managing the size change. You can use this object to animate your changes or get information about the transition that is in progress.
开始动手
首先为基类设置个约束条件(Protocol)
protocol ZWScreenTransitionProtocol: class {
/*
旋转或分屏情形下导致页面的Size变化后通过此代理方法来更新Controller subViews的布局
由于ipad不同方向且多任务分屏的存在,控件大小的布局尽量不要通过设置高度和宽度,尽量以左右、上下的相对位置来确定
size : CGSize 屏幕变化后的size
xScale : CGFloat 水平方向上的等比变化
xScale : CGFloat 数值方向上的等比变化
*/
func screenFrameTransitionTo(_ size: CGSize, xScale: CGFloat, yScale: CGFloat)
}
基类Controller中默认实现改协议,由子类来实现具体的适配
class ZWBaseViewController: UIViewController, ZWScreenTransitionProtocol {
func screenFrameTransitionTo(_ size: CGSize, xScale: CGFloat, yScale: CGFloat) {
//override by sub Class
}
}
基类Controller的extension中实现viewWillTransition(to:with:)方法(这里用extension主要是为了代码结构美观,没别的)
extension ZWBaseViewController {
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
//查看旋转的方向,刘海屏会用到(safeArea布局)
let orient = UIDevice.current.orientation
//屏幕改变后的Size
let newWidth: CGFloat = size.width
let newHeight: CGFloat = size.height
//屏幕改变前的Size
let oldWidth: CGFloat = self.view.frame.size.width
let oldHeight: CGFloat = self.view.frame.size.height
let xScale: CGFloat = newWidth / oldWidth
let yScale: CGFloat = newHeight / oldHeight
switch orient {
case .unknown:
currentOrient = .portrait
case .portrait:
currentOrient = .portrait
case .portraitUpsideDown:
currentOrient = .portraitUpsideDown
RLog.info("portraitUpsideDown")
case .landscapeLeft:
currentOrient = .landscapeLeft
RLog.info("landscapeLeft")
case .landscapeRight:
currentOrient = .landscapeRight
RLog.info("landscapeRight")
case .faceUp:
RLog.info("faceUp")
case .faceDown:
RLog.info("faceDown")
}
//触发protocol方法
screenFrameTransitionTo(size, xScale: xScale, yScale: yScale)
}
}
//Demo
class DemoController: ZWBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = "Main"
setupSubViews()
}
func setupSubViews() {
view.addSubview(tipLabel)
view.addSubview(printLabel)
view.addSubview(pushBtn)
view.addSubview(textField0)
view.addSubview(textField1)
layoutSubViews()
}
func layoutSubViews() {
screenFrameTransitionTo(self.view.frame.size, xScale: 1.0, yScale: 1.0)
}
//MARK: Property
lazy var tipLabel: UILabel = {
let label = UILabel()
label.textColor = .blue
label.textAlignment = .center
label.font = .systemFont(ofSize: 20.0)
label.text = "测试基类backHandler"
return label
}()
lazy var printLabel: UILabel = {
let label = UILabel()
label.textColor = .blue
label.textAlignment = .center
label.font = .systemFont(ofSize: 14.0)
return label
}()
lazy var pushBtn: UIButton = {
let btn = UIButton()
btn.setTitle("push", for: .normal)
btn.setTitle("push", for: .highlighted)
btn.setTitleColor(.white, for: .normal)
btn.setTitleColor(.white, for: .highlighted)
btn.backgroundColor = .red
btn.addTarget(self, action: #selector(pushToMainPage), for: .touchUpInside)
return btn
}()
lazy var textField0: UITextField = {
//没有左右布局,但是有宽度
let tf = UITextField()
tf.placeholder = "i am place holder"
tf.textColor = .black
tf.textAlignment = .left
tf.font = .systemFont(ofSize: 30.0)
tf.layer.borderColor = UIColor.blue.cgColor
tf.layer.borderWidth = 1.0
return tf
}()
lazy var textField1: UITextField = {
//有左右布局
let tf = UITextField()
tf.placeholder = "i am place holder"
tf.textColor = .black
tf.textAlignment = .left
tf.font = .systemFont(ofSize: 30.0)
tf.layer.borderColor = UIColor.blue.cgColor
tf.layer.borderWidth = 1.0
return tf
}()
}
//MARK: YFLayoutOrientProtocol
extension DemoController {
override func screenFrameTransitionTo(_ size: CGSize, xScale: CGFloat, yScale: CGFloat) {
tipLabel.snp.remakeConstraints { (make) in
//multipliedBy 不生效 -_-!!!??
// make.left.equalToSuperview().offset(20.0).multipliedBy(xScale)
make.left.equalToSuperview().offset(20.0 * xScale)
make.top.equalToSuperview().offset(120.0 * yScale)
}
printLabel.snp.remakeConstraints { (make) in
make.left.equalToSuperview().offset(20.0 * xScale)
make.top.equalTo(tipLabel.snp.bottom).offset(20.0 * yScale)
}
pushBtn.snp.remakeConstraints { (make) in
make.top.equalTo(printLabel.snp.bottom).offset(80 * yScale)
make.left.equalToSuperview().offset(20.0 * xScale)
make.size.equalTo(CGSize(width: 160.0, height: 24.0))
}
textField0.snp.remakeConstraints { (make) in
make.left.equalToSuperview().offset(20.0 * xScale)
make.top.equalTo(tipLabel.snp.bottom).offset(180.0 * yScale)
make.size.equalTo(CGSize(width: 300.0 * xScale, height: 100.0 * yScale))
}
textField1.snp.remakeConstraints { (make) in
make.left.equalToSuperview().offset(20.0 * xScale)
make.top.equalTo(tipLabel.snp.bottom).offset(340.0 * yScale)
make.right.equalToSuperview().offset(-30.0 * xScale)
make.height.equalTo(200.0 * yScale)
}
}
}

垂直
网友评论