It's common to have a horizontal scroll view embedded in a vertical scroll view - you just need to get the constraints set correctly.
Also, using the proper constraints, it's easy to have the scroll view's content control the scrollable area -- without having to calculate and explicitly set the .contentSize
.
Here is the layout. The main view background is Pink; the vertical scroll view is Yellow; the horizontal scroll view is Green:
The vertical scroll view is constrained to 0
on all 4 sides, and it's constrained Equal Width and Height to the main view.
The horizontal scroll view is constrained 0
for Leading, Top and Trailing (no Bottom constraint), and a Height constraint of 390
, and it's constrained Equal Width to the main view.
The image view is constrained Leading 10
with W/H of 40
.
The Title label is constrained to the image view.
The Description Label (number of lines = 0
) is constrained Leading to the image view, Width Equal to the vertical scroll view -20
(10 on the left and 10 on the right). And it's constrained 0
on the Bottom. As you add text to the label and its height grows, that will automatically increase the height of the vertical scroll view's scrollable area (its .contentSize
).
Here is the result, before and after scrolling:
And, for clarity, how it looks using Debug View Hierarchy:
To help you get it set up correctly, here's the controller class (no sizing code needed - all it's doing is adding text to the label):
class EmbeddedScrollViewController: UIViewController {
@IBOutlet var descriptionLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// 20 lines of text
descriptionLabel.text = (1...20).map({ "Line \($0)" }).joined(separator: "\n")
}
}
and the Storyboard source:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="1GW-r8-dyB">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Embedded Scroll View Controller-->
<scene sceneID="EkT-c0-tFZ">
<objects>
<viewController id="1GW-r8-dyB" customClass="EmbeddedScrollViewController" customModule="SW4Temp" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Mgr-6N-2U6">
<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="K2x-mz-KcZ" userLabel="V-Scroll">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Dcg-9m-tlK" userLabel="H-Scroll">
<rect key="frame" x="0.0" y="0.0" width="375" height="390"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Upper Left" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="unz-8T-JcR">
<rect key="frame" x="20" y="20" width="82" height="21"/>
<color key="backgroundColor" red="0.45138680930000002" green="0.99309605359999997" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Lower Right" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Cdr-yN-9YB">
<rect key="frame" x="500" y="330" width="90.5" height="21"/>
<color key="backgroundColor" red="0.45138680930000002" green="0.99309605359999997" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qsY-aV-AFa" userLabel="InfoLabel">
<rect key="frame" x="20" y="281" width="320" height="41"/>
<color key="backgroundColor" red="0.45138680930000002" green="0.99309605359999997" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="320" id="g2L-p3-Nt5"/>
</constraints>
<string key="text">To demonstrate Horizontal scrolling,
There is Another Label to the Right ---></string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.45009386540000001" green="0.98132258650000004" blue="0.4743030667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="390" id="2ln-JF-25C"/>
<constraint firstAttribute="bottom" secondItem="Cdr-yN-9YB" secondAttribute="bottom" constant="20" id="C6t-Uu-DXN"/>
<constraint firstItem="Cdr-yN-9YB" firstAttribute="top" secondItem="qsY-aV-AFa" secondAttribute="bottom" constant="8" id="GfU-jw-KzP"/>
<constraint firstItem="Cdr-yN-9YB" firstAttribute="leading" secondItem="qsY-aV-AFa" secondAttribute="trailing" constant="160" id="Q4e-Fl-IEg"/>
<constraint firstAttribute="trailing" secondItem="Cdr-yN-9YB" secondAttribute="trailing" constant="20" id="X5C-nj-47A"/>
<constraint firstItem="unz-8T-JcR" firstAttribute="leading" secondItem="Dcg-9m-tlK" secondAttribute="leading" constant="20" id="cVG-kM-8ZI"/>
<constraint firstItem="qsY-aV-AFa" firstAttribute="leading" secondItem="unz-8T-JcR" secondAttribute="leading" id="pPP-Ko-du2"/>
<constraint firstItem="qsY-aV-AFa" firstAttribute="top" secondItem="unz-8T-JcR" secondAttribute="bottom" constant="240" id="tMx-HW-l2L"/>
<constraint firstItem="unz-8T-JcR" firstAttribute="top" secondItem="Dcg-9m-tlK" secondAttribute="top" constant="20" id="ybo-xk-6LG"/>
</constraints>
</scrollView>
<pageControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="B7V-nL-rCv">
<rect key="frame" x="121.5" y="353" width="132" height="37"/>
<color key="backgroundColor" red="0.4756349325" green="0.47564673419999998" blue="0.47564041610000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="132" id="2ge-VP-yzz"/>
</constraints>
</pageControl>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="3cl-Ou-kTu">
<rect key="frame" x="10" y="405" width="40" height="40"/>
<color key="backgroundColor" red="0.0" green="0.58980089430000004" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="E0D-Ed-vVX"/>
<constraint firstAttribute="height" constant="40" id="MFN-Ap-lkV"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1Sf-bC-0yM">
<rect key="frame" x="58" y="415" width="70" height="21"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Description Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MkP-AG-X03">
<rect key="frame" x="10" y="461" width="355" height="20.5"/>
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="MkP-AG-X03" secondAttribute="bottom" constant="8" id="62d-uw-l6l"/>
<constraint firstItem="B7V-nL-rCv" firstAttribute="centerX" secondItem="Dcg-9m-tlK" secondAttribute="centerX" id="6TH-qD-Rpg"/>
<constraint firstItem="Dcg-9m-tlK" firstAttribute="leading" secondItem="K2x-mz-KcZ" secondAttribute="leading" id="8Cm-Zq-jKu"/>
<constraint firstItem="1Sf-bC-0yM" firstAttribute="centerY" secondItem="3cl-Ou-kTu" secondAttribute="centerY" id="D54-Jk-1zW"/>
<constraint firstItem="MkP-AG-X03" firstAttribute="width" secondItem="K2x-mz-KcZ" secondAttribute="width" constant="-20" id="Sk8-fq-0I8"/>
<constraint firstItem="3cl-Ou-kTu" firstAttribute="top" secondItem="Dcg-9m-tlK" secondAttribute="bottom" constant="15" id="XN2-Lz-nQQ"/>
<constraint firstAttribute="trailing" secondItem="Dcg-9m-tlK" secondAttribute="trailing" id="YtO-y4-qn9"/>
<constraint firstItem="MkP-AG-X03" firstAttribute="leading" secondItem="3cl-Ou-kTu" secondAttribute="leading" id="ZM0-3U-XLQ"/>
<constraint firstItem="Dcg-9m-tlK" firstAttribute="top" secondItem="K2x-mz-KcZ" secondAttribute="top" id="fxa-1i-NHa"/>
<constraint firstItem="Dcg-9m-tlK" firstAttribute="width" secondItem="K2x-mz-KcZ" secondAttribute="width" id="l7O-qV-Ja9"/>
<constraint firstItem="3cl-Ou-kTu" firstAttribute="leading" secondItem="K2x-mz-KcZ" secondAttribute="leading" constant="10" id="on9-FW-ZiG"/>
<constraint firstItem="B7V-nL-rCv" firstAttribute="bottom" secondItem="Dcg-9m-tlK" secondAttribute="bottom" id="tbv-ao-adS"/>
<constraint firstItem="1Sf-bC-0yM" firstAttribute="leading" secondItem="3cl-Ou-kTu" secondAttribute="trailing" constant="8" id="wuV-fj-HFV"/>
<constraint firstItem="MkP-AG-X03" firstAttribute="top" secondItem="3cl-Ou-kTu" secondAttribute="bottom" constant="16" id="x4z-IQ-o2z"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" red="1" green="0.1857388616" blue="0.57339501380000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="MMC-8B-qcF" firstAttribute="trailing" secondItem="K2x-mz-KcZ" secondAttribute="trailing" id="3S9-mL-Ldn"/>
<constraint firstItem="MMC-8B-qcF" firstAttribute="bottom" secondItem="K2x-mz-KcZ" secondAttribute="bottom" id="7g2-ph-w0I"/>
<constraint firstItem="K2x-mz-KcZ" firstAttribute="top" secondItem="MMC-8B-qcF" secondAttribute="top" id="PIT-lg-Z3r"/>
<constraint firstItem="K2x-mz-KcZ" firstAttribute="leading" secondItem="MMC-8B-qcF" secondAttribute="leading" id="irI-yU-v4c"/>
</constraints>
<viewLayoutGuide key="safeArea" id="MMC-8B-qcF"/>
</view>
<connections>
<outlet property="descriptionLabel" destination="MkP-AG-X03" id="4xr-iw-3tF"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="gbQ-wO-etq" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="41" y="2257"/>
</scene>
</scenes>
</document>
The Second Scroll View
the one on top, that you want to scroll horizontally? Are you using a textView instead of a label because it needs to be editable? – DonMag