Different layouts in portrait and landscape mode

后端 未结 9 1624
别跟我提以往
别跟我提以往 2020-12-28 14:16

Let\'s assume I have this layout design on an iPad Portrait.

But I would like to have it this way when the iPad is in landscape:

Is it possible to

9条回答
  •  隐瞒了意图╮
    2020-12-28 15:02

    The only way I have easily achieved this, so it works on iPads and iPhones is by doing it programmatically. This is done with Swift 5.0 in Xcode 10.2.

    In your ViewController, define the two views you want to change depending on orientation:

    @IBOutlet weak var raceInfoView: UIStackView!
    @IBOutlet weak var raceListView: UITableView!
    

    Then define the constraints which will always stay the same in your storyboard and define the ones which will change in your ViewController.

    private var portraitRaceInfoViewTrailing: NSLayoutConstraint!
    private var portraitRaceInfoViewBottom: NSLayoutConstraint!
    private var portraitRaceListViewLeading: NSLayoutConstraint!
    private var landscapeRaceInfoViewTrailing: NSLayoutConstraint!
    private var landscapeRaceInfoViewBottom: NSLayoutConstraint!
    private var landscapeRaceListViewTop: NSLayoutConstraint!
    

    Next, initialise the constraints, I put it in viewDidLoad but it can probably be put somewhere else.

    override func viewDidLoad() {
        super.viewDidLoad()
    
        portraitRaceInfoViewTrailing = NSLayoutConstraint(
            item: racesView as Any, attribute: NSLayoutConstraint.Attribute.trailing,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: raceInfoView, attribute: NSLayoutConstraint.Attribute.trailing,
            multiplier: 1, constant: 0)
        portraitRaceInfoViewBottom = NSLayoutConstraint(
            item: raceListView as Any, attribute: NSLayoutConstraint.Attribute.top,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: raceInfoView, attribute: NSLayoutConstraint.Attribute.bottom,
            multiplier: 1, constant: 0)
        portraitRaceListViewLeading = NSLayoutConstraint(
            item: raceListView as Any, attribute: NSLayoutConstraint.Attribute.leading,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: racesView, attribute: NSLayoutConstraint.Attribute.leading,
            multiplier: 1, constant: 0)
    
        landscapeRaceInfoViewTrailing = NSLayoutConstraint(
            item: raceListView as Any, attribute: NSLayoutConstraint.Attribute.leading,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: raceInfoView, attribute: NSLayoutConstraint.Attribute.trailing,
            multiplier: 1, constant: 0)
        landscapeRaceInfoViewBottom = NSLayoutConstraint(
            item: raceInfoView as Any, attribute: NSLayoutConstraint.Attribute.bottom,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: racesView, attribute: NSLayoutConstraint.Attribute.bottom,
            multiplier: 1, constant: 0)
        landscapeRaceListViewTop = NSLayoutConstraint(
            item: raceListView as Any, attribute: NSLayoutConstraint.Attribute.top,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: racesView, attribute: NSLayoutConstraint.Attribute.top,
            multiplier: 1, constant: 0)
    
        applyOrientationConstraints()
    }
    

    Declaring constraints programmatically looks a bit scary, but its actually quite easy. You can create the constraint in your storyboard and view all the values and copy the right ones to the right place in the code.

    And finally in viewDidLoad apply the constraints with applyOrientationConstraints().

    func applyOrientationConstraints() {
        let orient = UIApplication.shared.statusBarOrientation
        switch orient {
        case .portrait:
            NSLayoutConstraint.activate([portraitRaceInfoViewTrailing, portraitRaceInfoViewBottom, portraitRaceListViewLeading])
            NSLayoutConstraint.deactivate([landscapeRaceInfoViewTrailing, landscapeRaceInfoViewBottom, landscapeRaceListViewTop])
            break
        default:
            NSLayoutConstraint.deactivate([portraitRaceInfoViewTrailing, portraitRaceInfoViewBottom, portraitRaceListViewLeading])
            NSLayoutConstraint.activate([landscapeRaceInfoViewTrailing, landscapeRaceInfoViewBottom, landscapeRaceListViewTop])
            break
        }
    }
    

    And lastly override viewWillTransition to apply the constraints when the orientation changes.

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in
            self.applyOrientationConstraints()
        }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
            print("rotation completed")
        })
        super.viewWillTransition(to: size, with: coordinator)
    }
    

提交回复
热议问题