这样做的方法...
- 将顶部标签约束到“contentView”的顶部
- 将带有按钮的 stackView 约束到“contentView”的底部
- 从顶部标签底部限制 stackView 顶部 >= 70
- 将“contentView”的高度限制为 >= 滚动视图框架布局指南的高度
-
也将“contentView”的高度限制为等于滚动视图框架布局指南的高度,但优先级较低
- 您通常设置的所有其他约束
下面是它的外观:
并且,在运行时,有几组不同的文本/标题:
这是该控制器的情节提要源代码:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="r96-gX-wwR">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Scroll Example View Controller-->
<scene sceneID="4Qx-lW-r6i">
<objects>
<viewController id="r96-gX-wwR" customClass="ScrollExampleViewController" customModule="QuickTest" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="S6F-6v-wFA">
<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="fms-ps-iLx">
<rect key="frame" x="20" y="103.5" width="335" height="460"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="n1H-Aa-rGZ" userLabel="ContentView">
<rect key="frame" x="0.0" y="0.0" width="335" height="460"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1fs-iq-BVa">
<rect key="frame" x="20" y="20" width="295" height="41"/>
<color key="backgroundColor" red="0.83741801979999997" green="0.83743780850000005" blue="0.83742713930000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<string key="text">UILabel
(number of lines = 0, wordwrap)</string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="XxT-LJ-tha">
<rect key="frame" x="40" y="198" width="255" height="242"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0nb-3e-w4G" customClass="MultilineTitleButton" customModule="QuickTest" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="255" height="45.5"/>
<color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="contentEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
<state key="normal" title="Multiline Button 1">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<state key="highlighted">
<color key="titleColor" systemColor="systemRedColor"/>
</state>
<connections>
<action selector="didTap:" destination="r96-gX-wwR" eventType="touchUpInside" id="bYu-lb-kCi"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ip2-SI-4IG" customClass="MultilineTitleButton" customModule="QuickTest" customModuleProvider="target">
<rect key="frame" x="0.0" y="65.5" width="255" height="45.5"/>
<color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="contentEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
<state key="normal" title="Multiline Button 2">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<state key="highlighted">
<color key="titleColor" systemColor="systemRedColor"/>
</state>
<connections>
<action selector="didTap:" destination="r96-gX-wwR" eventType="touchUpInside" id="sra-Gt-kB6"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="x68-Yu-wG9" customClass="MultilineTitleButton" customModule="QuickTest" customModuleProvider="target">
<rect key="frame" x="0.0" y="131" width="255" height="45.5"/>
<color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="contentEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
<state key="normal" title="Multiline Button 3">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<state key="highlighted">
<color key="titleColor" systemColor="systemRedColor"/>
</state>
<connections>
<action selector="didTap:" destination="r96-gX-wwR" eventType="touchUpInside" id="nKy-zv-DRj"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="65G-cT-IFY" customClass="MultilineTitleButton" customModule="QuickTest" customModuleProvider="target">
<rect key="frame" x="0.0" y="196.5" width="255" height="45.5"/>
<color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<inset key="contentEdgeInsets" minX="12" minY="12" maxX="12" maxY="12"/>
<state key="normal" title="Multiline Button 4">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<state key="highlighted">
<color key="titleColor" systemColor="systemRedColor"/>
</state>
<connections>
<action selector="didTap:" destination="r96-gX-wwR" eventType="touchUpInside" id="qLv-lq-4Os"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.95236831899999996" green="0.86624437570000001" blue="0.86609393359999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="XxT-LJ-tha" firstAttribute="leading" secondItem="n1H-Aa-rGZ" secondAttribute="leading" constant="40" id="BKh-Wn-7pF"/>
<constraint firstItem="XxT-LJ-tha" firstAttribute="top" relation="greaterThanOrEqual" secondItem="1fs-iq-BVa" secondAttribute="bottom" constant="70" id="FRK-Bc-8jR"/>
<constraint firstItem="1fs-iq-BVa" firstAttribute="top" secondItem="n1H-Aa-rGZ" secondAttribute="top" constant="20" id="MRx-Ne-RhX"/>
<constraint firstItem="1fs-iq-BVa" firstAttribute="leading" secondItem="n1H-Aa-rGZ" secondAttribute="leading" constant="20" id="PjO-KU-pYX"/>
<constraint firstAttribute="trailing" secondItem="1fs-iq-BVa" secondAttribute="trailing" constant="20" id="QOs-Wt-QTT"/>
<constraint firstAttribute="bottom" secondItem="XxT-LJ-tha" secondAttribute="bottom" constant="20" id="VaZ-Xp-ps0"/>
<constraint firstAttribute="trailing" secondItem="XxT-LJ-tha" secondAttribute="trailing" constant="40" id="hiQ-NS-nMy"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemTealColor"/>
<constraints>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="width" secondItem="DTH-xk-U22" secondAttribute="width" id="0qP-Qh-tIf"/>
<constraint firstAttribute="height" constant="460" id="3K2-hl-Olf"/>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="trailing" secondItem="kfQ-fS-efa" secondAttribute="trailing" id="4qy-gg-Xv3"/>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="top" secondItem="kfQ-fS-efa" secondAttribute="top" id="HaN-b4-u0C"/>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="bottom" secondItem="kfQ-fS-efa" secondAttribute="bottom" id="Ne8-Ps-1QS"/>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="height" relation="greaterThanOrEqual" secondItem="DTH-xk-U22" secondAttribute="height" id="imC-1S-pfk"/>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="leading" secondItem="kfQ-fS-efa" secondAttribute="leading" id="pF3-CK-PA8"/>
<constraint firstItem="n1H-Aa-rGZ" firstAttribute="height" secondItem="DTH-xk-U22" secondAttribute="height" priority="250" id="qke-Uc-Q9Z"/>
</constraints>
<viewLayoutGuide key="contentLayoutGuide" id="kfQ-fS-efa"/>
<viewLayoutGuide key="frameLayoutGuide" id="DTH-xk-U22"/>
</scrollView>
</subviews>
<viewLayoutGuide key="safeArea" id="GZf-aI-xFl"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="fms-ps-iLx" firstAttribute="centerY" secondItem="S6F-6v-wFA" secondAttribute="centerY" id="FGd-ND-TjS"/>
<constraint firstItem="fms-ps-iLx" firstAttribute="leading" secondItem="GZf-aI-xFl" secondAttribute="leading" constant="20" id="cRD-FB-Z31"/>
<constraint firstItem="GZf-aI-xFl" firstAttribute="trailing" secondItem="fms-ps-iLx" secondAttribute="trailing" constant="20" id="yNr-VV-Wth"/>
</constraints>
</view>
<connections>
<outlet property="buttonStack" destination="XxT-LJ-tha" id="jgC-VB-ni5"/>
<outlet property="topLabel" destination="1fs-iq-BVa" id="a6p-gb-USC"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="alt-Fj-H3x" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="217" y="89"/>
</scene>
</scenes>
<designables>
<designable name="0nb-3e-w4G">
<size key="intrinsicContentSize" width="162" height="45.5"/>
</designable>
<designable name="65G-cT-IFY">
<size key="intrinsicContentSize" width="165" height="45.5"/>
</designable>
<designable name="Ip2-SI-4IG">
<size key="intrinsicContentSize" width="164.5" height="45.5"/>
</designable>
<designable name="x68-Yu-wG9">
<size key="intrinsicContentSize" width="165" height="45.5"/>
</designable>
</designables>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemRedColor">
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemTealColor">
<color red="0.35294117647058826" green="0.78431372549019607" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
还有一些示例代码 - 点击任何按钮都会循环显示几组数据:
@IBDesignable
class MultilineTitleButton: UIButton {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() -> Void {
self.titleLabel?.numberOfLines = 0
self.titleLabel?.textAlignment = .center
self.setContentHuggingPriority(UILayoutPriority.defaultLow + 1, for: .vertical)
self.setContentHuggingPriority(UILayoutPriority.defaultLow + 1, for: .horizontal)
layer.cornerRadius = 8
layer.borderWidth = 1
layer.borderColor = UIColor.black.cgColor
}
override var intrinsicContentSize: CGSize {
let size = self.titleLabel!.intrinsicContentSize
return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}
override func layoutSubviews() {
super.layoutSubviews()
titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width
}
}
class ScrollExampleViewController: UIViewController {
@IBOutlet var topLabel: UILabel!
@IBOutlet var buttonStack: UIStackView!
var sampleTitles: [[String]] = [
["Single", "Line", "Button", "Titles"],
["Single", "Line", "Button", "Titles"],
["Five\n2\n3\n4\n5", "Line\n2\n3\n4\n5", "Button\n2\n3\n4\n5", "Titles\n2\n3\n4\n5"],
["Various titles", "To demonstrate the amazing capabilities of auto-layout", "This set of titles should need to scroll", "This button (well, part of it) will be below the bottom of the scroll view."],
]
var infoStrings: [String] = [
"Short Top Label (no scrolling)",
"This is a longer string for the Top Label, so we can see it wrap onto multiple lines. Because we want at least 70-pts of vertical space to the 1st button, it should force the bottom button down far enough that we need a little bit of vertical scrolling.",
"This example shows our buttons each with Five lines of title text (lots of vertical scrolling).",
"This example is just to show that it continues to work when the four individual multiline title buttons have different heights.",
]
var titleSetIdx: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
infoStrings.append(topLabel.text ?? "No text in Top Label in Storyboard")
var storyboardTitles: [String] = []
buttonStack.arrangedSubviews.forEach { b in
if let btn = b as? UIButton {
storyboardTitles.append(btn.currentTitle ?? "Missing button title in Storyboard")
}
}
sampleTitles.append(storyboardTitles)
}
@IBAction func didTap(_ sender: Any) {
topLabel.text = infoStrings[titleSetIdx % infoStrings.count]
let a = sampleTitles[titleSetIdx % sampleTitles.count]
for (t, b) in zip(a, buttonStack.arrangedSubviews) {
if let btn = b as? UIButton {
btn.setTitle(t, for: [])
}
}
titleSetIdx += 1
}
}