Search code examples
autolayoutxibios-autolayout

Different portrait and landscape layouts with one xib?


enter image description here

I'm trying to achieve different design layouts with portrait and landscape orientation. The landscape orientation will have views that portrait orientation does not have. How can I have these two orientations in one XIB file and load them accordingly when the orientation changes?

I've tried this answer here but the landscape view does not look right. And when going from landscape back to portrait, the view gets shifted off the screen each time.


Solution

  • You can do this by using Vary for Traits - if you're not familiar with that, there are plenty of tutorials out there. This is probably a good starting point: https://www.raywenderlich.com/492-adaptive-layout-tutorial-in-ios-11-getting-started

    Essentially, you would start with standard phone portrait orientation: wC hR

    • Set top, leading, trailing and height constraints on Purple view.
    • Set top, leading, width and height constraints of Zero for Red view.
    • Set top, leading, width and height constraints of Zero for Blue view.

    Change to landscape orientation: wC hC

    • Add constraints to get your landscape layout, and delete any portrait layout constraints that are no longer needed.

    Here is a xib file with the constraints setup to get your desired result. Create a new xib, open it as source code, replace the entire source, and then re-open it as Interface Builder XIB Document:

    <?xml version="1.0" encoding="UTF-8"?>
    <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
        <device id="retina4_7" orientation="portrait">
            <adaptation id="fullscreen"/>
        </device>
        <dependencies>
            <deployment identifier="iOS"/>
            <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
            <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
            <capability name="Safe area layout guides" minToolsVersion="9.0"/>
            <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
        </dependencies>
        <objects>
            <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TraitTestView" customModule="SW4Temp" customModuleProvider="target"/>
            <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
            <view contentMode="scaleToFill" id="iN0-l3-epB">
                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                <subviews>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Purple" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="x2I-Wo-fEl">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="333.5"/>
                        <color key="backgroundColor" red="0.45490196078431372" green="0.52156862745098043" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <fontDescription key="fontDescription" type="boldSystem" pointSize="26"/>
                        <nil key="textColor"/>
                        <nil key="highlightedColor"/>
                    </label>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Red" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="w2j-KG-F8a">
                        <rect key="frame" x="375" y="0.0" width="0.0" height="0.0"/>
                        <color key="backgroundColor" red="0.97254901960784312" green="0.40392156862745099" blue="0.38039215686274508" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="height" id="AXD-eQ-1h9"/>
                            <constraint firstAttribute="width" id="tez-lx-gm1"/>
                        </constraints>
                        <fontDescription key="fontDescription" type="boldSystem" pointSize="26"/>
                        <nil key="textColor"/>
                        <nil key="highlightedColor"/>
                        <variation key="heightClass=compact">
                            <mask key="constraints">
                                <exclude reference="AXD-eQ-1h9"/>
                                <exclude reference="tez-lx-gm1"/>
                            </mask>
                        </variation>
                    </label>
                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Blue" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sXo-w2-aKd">
                        <rect key="frame" x="0.0" y="667" width="0.0" height="0.0"/>
                        <color key="backgroundColor" red="0.17254901960784313" green="0.59607843137254901" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="width" id="jIU-Ld-Txe"/>
                            <constraint firstAttribute="height" id="wOE-gF-bPQ"/>
                        </constraints>
                        <fontDescription key="fontDescription" type="boldSystem" pointSize="26"/>
                        <nil key="textColor"/>
                        <nil key="highlightedColor"/>
                        <variation key="heightClass=compact">
                            <mask key="constraints">
                                <exclude reference="jIU-Ld-Txe"/>
                                <exclude reference="wOE-gF-bPQ"/>
                            </mask>
                        </variation>
                    </label>
                </subviews>
                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                <constraints>
                    <constraint firstAttribute="bottom" secondItem="sXo-w2-aKd" secondAttribute="bottom" id="1T3-Jy-K0Z"/>
                    <constraint firstItem="x2I-Wo-fEl" firstAttribute="height" secondItem="iN0-l3-epB" secondAttribute="height" multiplier="0.5" id="8cP-nw-Azc"/>
                    <constraint firstItem="w2j-KG-F8a" firstAttribute="height" secondItem="x2I-Wo-fEl" secondAttribute="height" id="96S-1z-Dye"/>
                    <constraint firstItem="sXo-w2-aKd" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Bd2-O2-2Sf"/>
                    <constraint firstAttribute="trailing" secondItem="x2I-Wo-fEl" secondAttribute="trailing" id="Btf-sR-nFF"/>
                    <constraint firstItem="w2j-KG-F8a" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Feh-7O-9tt"/>
                    <constraint firstAttribute="trailing" secondItem="w2j-KG-F8a" secondAttribute="trailing" id="Gp9-jJ-YcU"/>
                    <constraint firstItem="x2I-Wo-fEl" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="XM4-sb-5fz"/>
                    <constraint firstAttribute="trailing" secondItem="sXo-w2-aKd" secondAttribute="trailing" constant="375" id="Ztc-MA-Jq0">
                        <variation key="heightClass=compact" constant="0.0"/>
                    </constraint>
                    <constraint firstItem="w2j-KG-F8a" firstAttribute="width" secondItem="x2I-Wo-fEl" secondAttribute="width" id="cYb-Dp-5J7"/>
                    <constraint firstItem="x2I-Wo-fEl" firstAttribute="height" secondItem="iN0-l3-epB" secondAttribute="height" multiplier="2:3" id="coI-el-yOt"/>
                    <constraint firstItem="sXo-w2-aKd" firstAttribute="top" secondItem="x2I-Wo-fEl" secondAttribute="bottom" constant="167" id="dbt-2z-a3G">
                        <variation key="heightClass=compact" constant="0.0"/>
                    </constraint>
                    <constraint firstItem="w2j-KG-F8a" firstAttribute="leading" secondItem="x2I-Wo-fEl" secondAttribute="trailing" constant="563.5" id="eia-Ec-aAO">
                        <variation key="heightClass=compact" constant="0.0"/>
                    </constraint>
                    <constraint firstItem="x2I-Wo-fEl" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="otL-1i-mP0"/>
                </constraints>
                <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
                <variation key="default">
                    <mask key="constraints">
                        <exclude reference="Ztc-MA-Jq0"/>
                        <exclude reference="coI-el-yOt"/>
                        <exclude reference="dbt-2z-a3G"/>
                        <exclude reference="96S-1z-Dye"/>
                        <exclude reference="cYb-Dp-5J7"/>
                        <exclude reference="eia-Ec-aAO"/>
                    </mask>
                </variation>
                <variation key="heightClass=compact">
                    <mask key="constraints">
                        <exclude reference="Btf-sR-nFF"/>
                        <include reference="Ztc-MA-Jq0"/>
                        <exclude reference="8cP-nw-Azc"/>
                        <include reference="coI-el-yOt"/>
                        <include reference="dbt-2z-a3G"/>
                        <include reference="96S-1z-Dye"/>
                        <include reference="cYb-Dp-5J7"/>
                        <include reference="eia-Ec-aAO"/>
                    </mask>
                </variation>
            </view>
        </objects>
    </document>
    

    Viewed as iPhone 8 Portrait:

    enter image description here

    Viewed as iPhone 8 Landscape:

    enter image description here


    Edit:

    If you need the same layout design for both iPhone and iPad, you can add this to your view controller class. Not necessarily recommended, but it should do the trick:

    override public var traitCollection: UITraitCollection {
    
        var desiredTraits = [UITraitCollection]()
    
        if view.bounds.width < view.bounds.height {
            desiredTraits = [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .regular)]
        } else {
            desiredTraits = [UITraitCollection(horizontalSizeClass: .compact), UITraitCollection(verticalSizeClass: .compact)]
        }
    
        return UITraitCollection(traitsFrom: desiredTraits)
    
    }
    

    Edit 2:

    If you need to work on your layout with the xib sized to iPad dimensions, you can do so.

    Open the xib in IB and select one of the phones for "View as:" - I chose the iPhone 8 - and Portrait orientation:

    enter image description here

    You see it shows wC hR traits, and the view will look like an iPhone 8 size and shape.

    Now, in the Attributes Inspector pane, change Size: Inferred to Size: Freeform:

    enter image description here enter image description here

    Next, select the Size Inspector pane, and change the size of the view to 768 x 1024:

    enter image description here

    You now have a Portrait Orientation "iPad" xib to design and set your wC hR constraints.

    When ready, select Landscape Orientation for "View as:"

    enter image description here

    You'll see the Traits change to wC hC -- but you won't see any change in your design view. So, go back to the Size Inspector pane and change the size to 1024 x 768:

    enter image description here

    Your design view now looks like an iPad in Landscape Orientation, and you can select Vary for Traits to configure your desired wC hC layout.

    While designing, you'll need to manually change the size each time you change the orientation, but you will see the trait changes.

    Now, Portrait in IB:

    enter image description here

    and, Landscape in IB:

    enter image description here