简体   繁体   English

多行按钮的自动布局问题

[英]Autolayout problem with multiline buttons

I have a UIScrollview with a contentview that contains 1 UILabel and 4 UIButtons of dynamic heights based on their content.我有一个带有内容视图的 UIScrollview,其中包含 1 个 UILabel 和 4 个基于其内容的动态高度 UIButton。 Please see image below.请看下图。

Now using Autolayout in interface builder, I want to position the UILabel at the top of the contentView and the group of buttons at the bottom of the contentView.现在在界面构建器中使用自动布局,我想将 UILabel 定位在 contentView 的顶部,将一组按钮定位在 contentView 的底部。 Keeping that in mind, I want to allow vertical spacing of >=70px between UILabel and the first UIButton and let the scrolling kick in if the label or buttons have large amount of text that goes beyond the visible area of UIScrollView.记住这一点,我希望在 UILabel 和第一个 UIButton 之间允许 >=70px 的垂直间距,如果标签或按钮有大量超出 UIScrollView 可见区域的文本,则让滚动开始。

I have tried to achieve this with label and buttons as subviews of the contentview and also with a UIStackView as a subview of the UIScrollview that contains UILabel as first element and an Inner Stackview for buttons as another element.我试图用标签和按钮作为 contentview 的子视图以及 UIStackView 作为 UIScrollview 的子视图来实现这一点,其中包含 UILabel 作为第一个元素和一个用于按钮的内部 Stackview 作为另一个元素。 However, I am not sure how the >=70 vertical spacing can be applied.但是,我不确定如何应用 >=70 垂直间距。 Thanks in advance.提前致谢。

在此处输入图片说明

The way to do this...这样做的方法...

  • constrain the Top Label to the Top of the "contentView"将顶部标签限制在“contentView”的顶部
  • constrain the stackView with the buttons to the Bottom of the "contentView"使用按钮将 stackView 限制在“contentView”的底部
  • constraint the stackView Top >= 70 from the Top Label Bottom从顶部标签底部约束 stackView Top >= 70
  • constrain the Height of the "contentView" to >= Height of the scroll view Frame Layout Guide将“contentView”的高度限制为 >= 滚动视图框架布局指南的高度
  • also constrain the Height of the "contentView" equal to Height of the scroll view Frame Layout Guide, but with a low Priority约束“contentView”的高度等于滚动视图框架布局指南的高度,但优先级较低
  • all other constraints as you would normally set them您通常设置的所有其他约束

Here is how it might look:这是它的外观:

在此处输入图片说明

and, at run-time, with a couple different sets of text / titles:并且,在运行时,有几组不同的文本/标题:

在此处输入图片说明 在此处输入图片说明

在此处输入图片说明 在此处输入图片说明

Here is Storyboard source for that controller:这是该控制器的 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>

and some example code - tapping any of the buttons will cycle through a couple sets of data:和一些示例代码 - 点击任何按钮将循环显示几组数据:

@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