问题描述
我有一个里面有 3 个动态标签的视图,我正在尝试找到一种方法在滚动视图中垂直居中,但是当它的动态标签太大而无法放在页面上时,让文本从顶部开始.Xcode 目前正在做的事情是这样的:
I have a view with 3 dynamic labels inside it and I am trying to find a way to centre it vertically in a scroll view but when its dynamic labels are too large to fit on a page, make the text start from the top. What Xcode is doing at the moment is this:
我想要做的是:
关于如何实现这一目标的任何想法?谢谢.
Any ideas about how to achieve this? Thanks.
推荐答案
您可以通过将标签嵌入堆栈视图并将堆栈视图嵌入 UIView 来完成此操作.标签文本会垂直展开stack view,也会垂直展开content view,会控制scroll view的.contentSize.
You can accomplish this by embedding the labels in a stack view and embedding the stack view in a UIView. The label text will expand the stack view vertically, which will expand the content view vertically, which will control the scroll view's .contentSize.
黑色是滚动视图;蓝色是内容视图;堆栈视图仅显示为细灰色轮廓;标签是黄色、绿色和青色.背景颜色只是让您更容易看到是什么.
Black is the scroll view; blue is the content view; stack view only shows as thin gray outline; labels are yellow, green and cyan. The background colors just make it easier to see what's what.
一堆步骤,但应该清楚:
Bunch of steps, but should be clear:
- 添加一个scrollView,照常设置约束
- 将 UIView 添加到 scrollView - 将其命名为contentView"
- 将 contentView 的 top/leading/trailing/bottom 设置为 scrollView 的约束 0
- 设置contentView的宽高等于scrollView的宽高
- 向 contentView 添加一个 stackView
- 将stackView设置为垂直/填充/填充/间距:20
- 将 stackView 约束设置为 top: 8, bottom: 8,leading: 40, trailing: 40 到 contentView
- 将 stackView centerY 约束设置为 contentView
- 给 stackView 添加三个标签
- 设置字体和文本,设置中心和底部标签的行数 = 0
- 将 stackView 顶部和底部约束更改为 >= 8
- 将 contentView 高度限制更改为 Priority: 250
- 我认为这就是一切......
将 contentView 的 height Priority 设置为 250 将允许它根据标签中的文本垂直扩展.
Setting the height Priority of the contentView to 250 will allow it to expand vertically based on the text in the labels.
将 stackView 的顶部和底部约束设置为 >= 8 将推动" contentView 的顶部和底部,但当您没有足够的文本超出垂直边界时会留出额外空间.
Setting top and bottom stackView constraints to >= 8 will "push" the top and bottom of the contentView, but allow extra space when you don't have enough text to exceed the vertical bounds.
结果:
这是一个故事板,所有内容都已准备好供参考:
Here's a storyboard with everything in place for reference:
<?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="SeU-GX-TTY"> <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> <!--View Controller--> <scene sceneID="bCz-Kd-LLi"> <objects> <viewController id="SeU-GX-TTY" sceneMemberID="viewController"> <view key="view" contentMode="scaleToFill" id="qjW-fW-J5n"> <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="Zj2-9M-SP5" userLabel="scrollView"> <rect key="frame" x="0.0" y="40" width="375" height="627"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Pmb-IH-ckB" userLabel="contentView"> <rect key="frame" x="0.0" y="0.0" width="375" height="627"/> <subviews> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="EfQ-93-hcI" userLabel="stackView"> <rect key="frame" x="40" y="164" width="295" height="299.5"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Anger" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Sxz-f7-zjR" userLabel="topLabel"> <rect key="frame" x="0.0" y="0.0" width="295" height="43"/> <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <fontDescription key="fontDescription" type="system" pointSize="36"/> <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="STy-4u-e1W" userLabel="centerLabel"> <rect key="frame" x="0.0" y="63" width="295" height="183"/> <color key="backgroundColor" red="0.83216959239999999" green="0.98548370600000001" blue="0.47333085539999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <string key="text">Anger is an intense emotion defined as a response to a perceived provocation, the invasion of one's boundaries, or a threat. From an evolutionary standpoint, anger servers to mobilise psychological resources in order to address the threat/invasion. Anger is directed at an individual of equal status.</string> <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" verticalCompressionResistancePriority="749" text="Based on information from Wikipedia. APA DIctionary of Psycology" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="u3i-zP-e1M" userLabel="bottomLabel"> <rect key="frame" x="0.0" y="266" width="295" height="33.5"/> <color key="backgroundColor" red="0.45138680930000002" green="0.99309605359999997" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <fontDescription key="fontDescription" type="system" pointSize="14"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> </subviews> </stackView> </subviews> <color key="backgroundColor" red="0.46202266219999999" green="0.83828371759999998" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstAttribute="trailing" secondItem="EfQ-93-hcI" secondAttribute="trailing" constant="40" id="4HE-oJ-RE3"/> <constraint firstItem="EfQ-93-hcI" firstAttribute="centerY" secondItem="Pmb-IH-ckB" secondAttribute="centerY" id="H9O-jj-a7A"/> <constraint firstItem="EfQ-93-hcI" firstAttribute="top" relation="greaterThanOrEqual" secondItem="Pmb-IH-ckB" secondAttribute="top" constant="8" id="cKe-DN-Lbn"/> <constraint firstItem="EfQ-93-hcI" firstAttribute="leading" secondItem="Pmb-IH-ckB" secondAttribute="leading" constant="40" id="f4g-6a-VqH"/> <constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="EfQ-93-hcI" secondAttribute="bottom" constant="8" id="meR-gT-OVG"/> </constraints> </view> </subviews> <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="Pmb-IH-ckB" firstAttribute="top" secondItem="Zj2-9M-SP5" secondAttribute="top" id="HCI-bq-7ur"/> <constraint firstAttribute="trailing" secondItem="Pmb-IH-ckB" secondAttribute="trailing" id="Tdl-c0-GAV"/> <constraint firstItem="Pmb-IH-ckB" firstAttribute="width" secondItem="Zj2-9M-SP5" secondAttribute="width" id="Zj9-ND-Fqt"/> <constraint firstItem="Pmb-IH-ckB" firstAttribute="leading" secondItem="Zj2-9M-SP5" secondAttribute="leading" id="ckv-wi-E1z"/> <constraint firstItem="Pmb-IH-ckB" firstAttribute="height" secondItem="Zj2-9M-SP5" secondAttribute="height" priority="250" id="jpK-HZ-vva"/> <constraint firstAttribute="bottom" secondItem="Pmb-IH-ckB" secondAttribute="bottom" id="psz-UW-bNp"/> </constraints> </scrollView> </subviews> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <constraints> <constraint firstItem="Zj2-9M-SP5" firstAttribute="top" secondItem="Xr7-LW-bbC" secondAttribute="top" constant="20" id="EgA-Bk-3fC"/> <constraint firstItem="Zj2-9M-SP5" firstAttribute="leading" secondItem="qjW-fW-J5n" secondAttribute="leading" id="MBG-pL-R8Q"/> <constraint firstItem="Xr7-LW-bbC" firstAttribute="bottom" secondItem="Zj2-9M-SP5" secondAttribute="bottom" id="e9K-6A-Y9F"/> <constraint firstItem="Xr7-LW-bbC" firstAttribute="trailing" secondItem="Zj2-9M-SP5" secondAttribute="trailing" id="yfs-wt-Br8"/> </constraints> <viewLayoutGuide key="safeArea" id="Xr7-LW-bbC"/> </view> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="lHx-xL-Vx5" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> <point key="canvasLocation" x="225" y="106"/> </scene> </scenes> </document>
这是一个仅通过代码复制该布局/功能的快速示例:
And here's a quick example replicating that layout / functionality via code only:
// // ScrollWorkViewController.swift // // Created by DonMag on 6/12/19. // import UIKit class ScrollWorkViewController: UIViewController { let theScrollView: UIScrollView = { let v = UIScrollView() v.backgroundColor = .red return v }() let contentView: UIView = { let v = UIView() v.backgroundColor = UIColor(red: 0.25, green: 0.25, blue: 1.0, alpha: 1.0) return v }() let stackView: UIStackView = { let v = UIStackView() v.axis = .vertical v.alignment = .fill v.distribution = .fill v.spacing = 20 return v }() let topLabel: UILabel = { let v = UILabel() v.font = UIFont.boldSystemFont(ofSize: 32.0) v.backgroundColor = .yellow return v }() let centerLabel: UILabel = { let v = UILabel() v.font = UIFont.systemFont(ofSize: 17.0) v.numberOfLines = 0 v.backgroundColor = .green return v }() let bottomLabel: UILabel = { let v = UILabel() v.font = UIFont.systemFont(ofSize: 14.0) v.numberOfLines = 0 v.backgroundColor = .cyan return v }() override func viewDidLoad() { super.viewDidLoad() [theScrollView, contentView, stackView, topLabel, centerLabel, bottomLabel].forEach { $0.translatesAutoresizingMaskIntoConstraints = false } view.addSubview(theScrollView) theScrollView.addSubview(contentView) contentView.addSubview(stackView) stackView.addArrangedSubview(topLabel) stackView.addArrangedSubview(centerLabel) stackView.addArrangedSubview(bottomLabel) let contentViewHeightConstraint = contentView.heightAnchor.constraint(equalTo: theScrollView.heightAnchor, constant: 0.0) contentViewHeightConstraint.priority = .defaultLow NSLayoutConstraint.activate([ // constrain all 4 sides of the scroll view to the safe area theScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0), theScrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0.0), theScrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0.0), theScrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0), // constrain all 4 sides of the content view to the scroll view contentView.topAnchor.constraint(equalTo: theScrollView.topAnchor, constant: 0.0), contentView.bottomAnchor.constraint(equalTo: theScrollView.bottomAnchor, constant: 0.0), contentView.leadingAnchor.constraint(equalTo: theScrollView.leadingAnchor, constant: 0.0), contentView.trailingAnchor.constraint(equalTo: theScrollView.trailingAnchor, constant: 0.0), // constrain width of content view to width of scroll view contentView.widthAnchor.constraint(equalTo: theScrollView.widthAnchor, constant: 0.0), // constrain the stack view >= 8-pts from the top // <= minus 8-pts from the bottom // 40-pts leading and trailing stackView.topAnchor.constraint(greaterThanOrEqualTo: contentView.topAnchor, constant: 8.0), stackView.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -8.0), stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 40.0), stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -40.0), // constrain stack view centerY to contentView centerY stackView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0.0), // activate the contentView's height constraint contentViewHeightConstraint, ]) topLabel.text = "Anger" bottomLabel.text = "Based on information from Wikipedia APA Dictionary of Psychology" // a sample paragraph of text let centerSampleText = "Anger is an intense emotion defined as a response to a perceived provocation, the invasion of one’s boundaries, or a threat. From an evolutionary standpoint, anger servers to mobilise psychological resources in order to address the threat/invasion. Anger is directed at an individual of equal status." // change to repeat the center-label sample text let numberOfParagraphs = 2 var s = "" for i in 1...numberOfParagraphs { s += "(i). " + centerSampleText if i < numberOfParagraphs { s += " " } } centerLabel.text = s } }