【问题标题】:Autolayout problem with multiline buttons多行按钮的自动布局问题
【发布时间】:2021-12-23 02:13:29
【问题描述】:

我有一个 UIScrollview,其内容视图包含 1 个 UILabel 和 4 个基于其内容的动态高度的 UIButton。请看下图。

现在在界面生成器中使用自动布局,我想将 UILabel 定位在 contentView 的顶部,并将按钮组定位在 contentView 的底部。牢记这一点,我希望在 UILabel 和第一个 UIButton 之间允许 >=70px 的垂直间距,如果标签或按钮的大量文本超出 UIScrollView 的可见区域,则让滚动开始。

我尝试使用标签和按钮作为 contentview 的子视图以及 UIStackView 作为 UIScrollview 的子视图,其中包含 UILabel 作为第一个元素,按钮的内部 Stackview 作为另一个元素。但是,我不确定如何应用 >=70 垂直间距。提前致谢。

【问题讨论】:

    标签: swift autolayout


    【解决方案1】:

    这样做的方法...

    • 将顶部标签约束到“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
        }
        
    }
    

    【讨论】:

      猜你喜欢
      • 2014-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多