一、优化布局
在iOS中,尤其是在iPad上,用户有多种方式使用设备,因此应用程序需要支持不同的方向和分辨率。这意味着应用程序的布局必须能够在小屏幕或大屏幕上自适应并固定。如下所示,我们将通过控制器和约束来解决布局适应问题:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) setupLayout() } private func setupLayout() { view.addSubview(titleLabel) titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true titleLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true } @objc func willEnterForeground() { // Update constraints if screen is rotated view.layoutIfNeeded() setupLayout() }
通过监听应用“willEnterForegroundNotification”通知,使控制器重新调整布局。同时,约束可先参照“参考控制器”的示例约束代码:
func setupConstraints() { backgroundImageV.snp.remakeConstraints { (make) in make.edges.equalTo(self.view).inset(UIEdgeInsets.zero) } scrollView.snp.makeConstraints { (make) in make.width.equalTo(self.view.snp.width).offset(-30) make.centerX.equalTo(self.view.snp.centerX) make.top.equalTo(self.view.snp.topMargin).offset(50) make.bottom.equalTo(self.view.snp.bottomMargin).offset(-10) } contentView.snp.makeConstraints { (make) in make.edges.equalTo(scrollView.snp.edges) make.width.equalTo(scrollView.snp.width) } }
二、处理设备的转向事件
iOS支持两种设备方向:纵向和横向。这意味着你需要根据方向调整你的视图。例如,你在纵向方向下可能有一个大的标题,但是在横向方向下这个标题可能会对用户来说太小,不能完全显示。为了解决这个问题,你需要使用UIViewController类的以下方法:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) // Do some action when device orientation is changed if traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass || traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass { setupLayout() } }
通过监听属性值的改变,调用“setupLayout()”方法,来改变布局和约束
三、适配各个设备尺寸
一个好的iOS应用程序应该被设计用于应对各种屏幕尺寸,包括iPhone、iPad、Apple Watch和Apple TV。你可以使用以下技术来适配各个设备尺寸:
1、使用Size Class和Auto Layout来使控制器自适应不同尺寸的屏幕;
2、对于iPhone,使用Dynamic Type和Auto Layout调整字体尺寸;
3、使用Universal Storyboard来创建一个单一的Storyboard适应所有设备;
如下所示,我们将采用一系列技术适应各种设备尺寸:
override func viewDidLoad() { super.viewDidLoad() if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular { // iPhone portrait setupLayoutForIPhone() } else if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .compact { // iPhone landscape setupLayoutForIPhone() } else if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass == .regular { // iPad portrait and landscape setupLayoutForIPad() } }
上述代码实现了对各种设备方向的自适应处理,具体实现方法可参照“优化布局”一节所述的约束方法。
四、处理考虑全面的适配问题
设备的多样性和不断增长的分辨率,对iOS应用程序的适配提出了新的要求。仅迎合设备的横向或纵向方向,换句话说,只是“垂直模式”或“水平模式”的适配已不再足够。因此,更加全面的适配问题需处理。为了解决这个问题,iOS应用程序需要考虑全面的适配因素,如以下适配技术:
1、使用Size Class和Auto Layout;
2、使用不同的图片尺寸;
3、使用不同的字体尺寸和样式;
4、使用代码适配;
下述代码给出一个全面适配iOS设备的示例:
enum DeviceOrientation { case portrait case landscapeLeft case landscapeRight } private func updateLayout(for orientation: DeviceOrientation) { if orientation == .portrait { // Set portrait layout constraints profilePictureViewTopConstraint.constant = 50 profilePictureViewLeftConstraint.constant = 20 nameLabelTopConstraint.constant = 50 nameLabelLeftConstraint.constant = 120 hobbiesLabelTopConstraint.constant = 80 hobbiesLabelLeftConstraint.constant = 120 } else { // Set landscape layout constraints profilePictureViewTopConstraint.constant = 20 profilePictureViewLeftConstraint.constant = 20 nameLabelTopConstraint.constant = 20 nameLabelLeftConstraint.constant = 120 hobbiesLabelTopConstraint.constant = 70 hobbiesLabelLeftConstraint.constant = 120 } }
上述代码定义了一个“DeviceOrientation”枚举类型和一个“updateLayout(for: DeviceOrientation)”方法。该方法接收一个“DeviceOrientation”枚举类型参数,通过枚举来设置portrait和landscape方向下的约束,来实现全面的设备适配。