Search code examples
iosswiftuiscrollviewuiimageviewautolayout

Dynamic sized UIImageView in UIScrollView with some complex conditions


How should I configure AutoLayouts if I want to create this kind of layout? Or let me know if it's impossible by only AutoLayout.

[UIView]
  [UIScrollView]
    [UIImageView]
    [UILabel]
    [UIButton]

Conditions I want to realize:

  • UIImageView:
    • width:height = 1:1 (Aspect Ratio = 1:1)
    • width <= UIView.width (Max Width)
    • width >= UIView.width*70% (Min Width)
  • If screen size is large enough, UIImageView should expand to Max Width and scrolling is not needed.
  • If screen size is not large enough but can be shown in its Min Width without any scrolling, UIImageView should shrink to Min Width and scrolling is not needed (ie. all subviews is shown without any scroll).
  • If screen size is not large enough and scrolling is needed even if UIImageView shrinks to Min Width, UIImageView should shrink to Min Width and scrolling is needed (ie. NOT all subviews is shown without any scroll).

Solution

  • This might do the trick for you...

    Kinda tough to explain everything, but you should be able to follow the constraints in the image. The only thing you cannot see is that the multi-line label must have its Content Compression Resistance Priority set to Required (1000).

    The idea is to set constraints with specific Priority values so auto-layout will try to make the image view width - at 998 Priority - as wide as the scroll view, but allow it to shrink to a minimum width of 70% as the content below it grows. When it reaches 70%, it will not get any smaller, and the combined heights of the image view + label + button will force the "content" view to expand vertically, as it has a height constraint of 999.

    Here the label has 7 lines of text, with a font size of 18:

    enter image description here

    And here's how it looks with the font size increased to 28 - notice that the image view is now less-than the full width of the scroll view:

    enter image description here

    and now, with the font size increased to 36, we see that the image view is at its min width of 70%, and the button has been pushed down past the bottom of the scroll view's frame (so everything will scroll):

    enter image description here

    Here's the source for the Storyboard - play around with the font-size and/or the amount of text in the label to see it work:

    <?xml version="1.0" encoding="UTF-8"?>
    <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="eB4-FG-006">
        <device id="retina4_7" orientation="portrait">
            <adaptation id="fullscreen"/>
        </device>
        <dependencies>
            <deployment identifier="iOS"/>
            <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
            <capability name="Safe area layout guides" minToolsVersion="9.0"/>
            <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
        </dependencies>
        <scenes>
            <!--View Controller-->
            <scene sceneID="cKl-8C-enU">
                <objects>
                    <viewController id="eB4-FG-006" sceneMemberID="viewController">
                        <view key="view" contentMode="scaleToFill" id="qMY-Qc-gio">
                            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <subviews>
                                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="q6G-7e-kz1">
                                    <rect key="frame" x="20" y="60" width="335" height="567"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mbq-g1-m6Z" userLabel="ContentView">
                                            <rect key="frame" x="0.0" y="0.0" width="335" height="567"/>
                                            <subviews>
                                                <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="N7z-eO-cci">
                                                    <rect key="frame" x="0.0" y="0.0" width="335" height="335"/>
                                                    <color key="backgroundColor" red="0.0" green="0.97680455450000003" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <constraints>
                                                        <constraint firstAttribute="width" secondItem="N7z-eO-cci" secondAttribute="height" multiplier="1:1" id="3Za-Q8-IFq"/>
                                                    </constraints>
                                                </imageView>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Pp5-EQ-8Vh" userLabel="Multi-LineLabel">
                                                    <rect key="frame" x="142.5" y="343" width="50" height="150.5"/>
                                                    <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <string key="text">Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    Line 6
    Line 7</string>
                                                    <fontDescription key="fontDescription" type="system" pointSize="18"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rg8-I7-3hZ">
                                                    <rect key="frame" x="144.5" y="501.5" width="46" height="30"/>
                                                    <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <constraints>
                                                        <constraint firstAttribute="height" constant="30" id="NZU-hx-0M5"/>
                                                    </constraints>
                                                    <state key="normal" title="Button"/>
                                                </button>
                                            </subviews>
                                            <color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <constraints>
                                                <constraint firstItem="rg8-I7-3hZ" firstAttribute="top" secondItem="Pp5-EQ-8Vh" secondAttribute="bottom" constant="8" id="6c5-vJ-c8B"/>
                                                <constraint firstItem="rg8-I7-3hZ" firstAttribute="centerX" secondItem="mbq-g1-m6Z" secondAttribute="centerX" id="C6W-uG-Irk"/>
                                                <constraint firstItem="Pp5-EQ-8Vh" firstAttribute="centerX" secondItem="mbq-g1-m6Z" secondAttribute="centerX" id="MDd-eI-O2X"/>
                                                <constraint firstItem="Pp5-EQ-8Vh" firstAttribute="top" secondItem="N7z-eO-cci" secondAttribute="bottom" constant="8" id="Ozv-Hn-EbX"/>
                                                <constraint firstItem="N7z-eO-cci" firstAttribute="top" secondItem="mbq-g1-m6Z" secondAttribute="top" id="Qbn-EK-zhn"/>
                                                <constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="rg8-I7-3hZ" secondAttribute="bottom" constant="8" id="XRT-bz-2bI"/>
                                                <constraint firstItem="rg8-I7-3hZ" firstAttribute="top" secondItem="Pp5-EQ-8Vh" secondAttribute="bottom" constant="8" id="bny-1w-xOv"/>
                                                <constraint firstItem="N7z-eO-cci" firstAttribute="width" relation="greaterThanOrEqual" secondItem="mbq-g1-m6Z" secondAttribute="width" multiplier="0.7" id="bsP-M1-7uP"/>
                                                <constraint firstItem="N7z-eO-cci" firstAttribute="width" secondItem="mbq-g1-m6Z" secondAttribute="width" priority="998" id="fr8-4U-00h"/>
                                                <constraint firstItem="N7z-eO-cci" firstAttribute="centerX" secondItem="mbq-g1-m6Z" secondAttribute="centerX" id="hVh-Ld-mDS"/>
                                            </constraints>
                                        </view>
                                    </subviews>
                                    <color key="backgroundColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <constraints>
                                        <constraint firstAttribute="trailing" secondItem="mbq-g1-m6Z" secondAttribute="trailing" id="Fbg-Dx-idJ"/>
                                        <constraint firstAttribute="bottom" secondItem="mbq-g1-m6Z" secondAttribute="bottom" id="Hrx-mL-t1p"/>
                                        <constraint firstItem="mbq-g1-m6Z" firstAttribute="top" secondItem="q6G-7e-kz1" secondAttribute="top" id="La2-Bo-p6J"/>
                                        <constraint firstItem="mbq-g1-m6Z" firstAttribute="leading" secondItem="q6G-7e-kz1" secondAttribute="leading" id="S8w-du-yf0"/>
                                        <constraint firstItem="mbq-g1-m6Z" firstAttribute="height" secondItem="q6G-7e-kz1" secondAttribute="height" priority="999" id="lWB-wI-t5Q"/>
                                        <constraint firstItem="mbq-g1-m6Z" firstAttribute="width" secondItem="q6G-7e-kz1" secondAttribute="width" id="ynr-jB-Phr"/>
                                    </constraints>
                                </scrollView>
                            </subviews>
                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstItem="ASm-Jv-0JK" firstAttribute="trailing" secondItem="q6G-7e-kz1" secondAttribute="trailing" constant="20" id="27b-fv-IjT"/>
                                <constraint firstItem="q6G-7e-kz1" firstAttribute="leading" secondItem="ASm-Jv-0JK" secondAttribute="leading" constant="20" id="4sv-oj-8jc"/>
                                <constraint firstItem="q6G-7e-kz1" firstAttribute="top" secondItem="ASm-Jv-0JK" secondAttribute="top" constant="40" id="KKa-P9-1oI"/>
                                <constraint firstItem="ASm-Jv-0JK" firstAttribute="bottom" secondItem="q6G-7e-kz1" secondAttribute="bottom" constant="40" id="b3R-Aw-brw"/>
                            </constraints>
                            <viewLayoutGuide key="safeArea" id="ASm-Jv-0JK"/>
                        </view>
                    </viewController>
                    <placeholder placeholderIdentifier="IBFirstResponder" id="zh5-Lh-ZPo" userLabel="First Responder" sceneMemberID="firstResponder"/>
                </objects>
                <point key="canvasLocation" x="806" y="-161"/>
            </scene>
        </scenes>
    </document>