Programmatically implementing two different layouts using size classes

前端 未结 4 1703
清歌不尽
清歌不尽 2021-01-30 16:54

I have a four buttons layout. In portrait they should be shown one above the other. In landscape they should be in two columns each with two buttons.

I implement the but

相关标签:
4条回答
  • 2021-01-30 17:00

    Swift 4 code for the accepted answer:

    if (self.view.traitCollection.horizontalSizeClass == .compact) {
    ...
    }
    
    0 讨论(0)
  • 2021-01-30 17:04

    traitCollection only works in iOS8. So your app will crash on iOS7. Use the code below to support both iOS7 and iOS8

    if ([self.view respondsToSelector:@selector(traitCollection)]){
    
        if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
        ...
        }
    
    }
    
    0 讨论(0)
  • 2021-01-30 17:06

    You can examine the view's trait collection to determine its horizontal and vertical size class.

    if (self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
        ...
    }
    

    Implement the traitCollectionDidChange: method to automatically be called when a trait changes due to autorotation.

    For more information, see UITraitCollection Class Reference and UITraitEnvironment Protocol Reference.

    0 讨论(0)
  • 2021-01-30 17:09

    In the meantime I have found a good solution. Since this question has so many upvotes, I thought I would quickly describe it. I was inspired to this solution by a WWDC session.

    I have moved on to Swift so please excuse that the code will be in swift - the concept is however the same for Obj-C.

    You start out by declaring three constraint arrays:

     // Constraints
     private var compactConstraints: [NSLayoutConstraint] = []
     private var regularConstraints: [NSLayoutConstraint] = []
     private var sharedConstraints: [NSLayoutConstraint] = []
    

    And then you fill the constraints accordingly. You can i.e. do this in a separate function that you call from viewDidLoad or you do it in viewDidLoad directly.

    sharedConstraints.append(contentsOf: [
         btnStackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
        ...
    ])
    
    compactConstraints.append(contentsOf: [
         btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.7),
        ...
    ])
    
    regularConstraints.append(contentsOf: [
         btnStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.4),
        ...
    ])
    

    The important part is switching between the size classes and activating/deactivating the appropriate constraints.

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    
        super.traitCollectionDidChange(previousTraitCollection)
    
        if (!sharedConstraints[0].isActive) {
           // activating shared constraints
           NSLayoutConstraint.activate(sharedConstraints)
        }
    
    
        if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular {
            if regularConstraints.count > 0 && regularConstraints[0].isActive {
                NSLayoutConstraint.deactivate(regularConstraints)
            }
            // activating compact constraints
            NSLayoutConstraint.activate(compactConstraints)
        } else {
            if compactConstraints.count > 0 && compactConstraints[0].isActive {
                NSLayoutConstraint.deactivate(compactConstraints)
            }
            // activating regular constraints
            NSLayoutConstraint.activate(regularConstraints)
        }
    }
    

    I know that the constraints don't fit to the ones in the question. But the constraints themselves are irrelevant. The main thing is how one switches between two sets of constraints based on the size class.

    Hope this helps.

    0 讨论(0)
提交回复
热议问题