簡體   English   中英

多行按鈕的自動布局問題

[英]Autolayout problem with multiline buttons

我有一個帶有內容視圖的 UIScrollview,其中包含 1 個 UILabel 和 4 個基於其內容的動態高度 UIButton。 請看下圖。

現在在界面構建器中使用自動布局,我想將 UILabel 定位在 contentView 的頂部,將一組按鈕定位在 contentView 的底部。 記住這一點,我希望在 UILabel 和第一個 UIButton 之間允許 >=70px 的垂直間距,如果標簽或按鈕有大量超出 UIScrollView 可見區域的文本,則讓滾動開始。

我試圖用標簽和按鈕作為 contentview 的子視圖以及 UIStackView 作為 UIScrollview 的子視圖來實現這一點,其中包含 UILabel 作為第一個元素和一個用於按鈕的內部 Stackview 作為另一個元素。 但是,我不確定如何應用 >=70 垂直間距。 提前致謝。

在此處輸入圖片說明

這樣做的方法...

  • 將頂部標簽限制在“contentView”的頂部
  • 使用按鈕將 stackView 限制在“contentView”的底部
  • 從頂部標簽底部約束 stackView Top >= 70
  • 將“contentView”的高度限制為 >= 滾動視圖框架布局指南的高度
  • 約束“contentView”的高度等於滾動視圖框架布局指南的高度,但優先級較低
  • 您通常設置的所有其他約束

這是它的外觀:

在此處輸入圖片說明

並且,在運行時,有幾組不同的文本/標題:

在此處輸入圖片說明 在此處輸入圖片說明

在此處輸入圖片說明 在此處輸入圖片說明

這是該控制器的 Storyboard 源代碼:

<?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
    }
    
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM