在界面生成器中,如何通过约束最小化滚动视图大小?

问题描述 投票:0回答:1

我有我的视图控制器和 xib 文件。在 xib 文件中,在主视图上我有一个子视图。子视图包含按钮上方的滚动视图。滚动视图的内容视图包含文本标签和文本视图。文本标签和文本视图的字符串源自字符串文件。文本视图的第二个文本可能来自多个文件之一,并且往往具有较大的文本,但情况有所不同。文本视图不可滚动。该按钮的高度是固定的。

我想要什么 - 包含滚动视图和按钮的 UIView 需要根据滚动视图的内容来增大或缩小,但是包含所有内容的 UIView 也不应该增长到大于设备屏幕的顶部和底部约束。如果可能的话,滚动视图应将其大小最小化为内容视图的大小。如果两个文本标签的大小(由于它们的字符串大小)足够大,则滚动视图应该根据其内容视图增长以匹配该大小,直到包含它和按钮的 UIView 的大小适合。一旦包含滚动视图和按钮的 UIView 达到其最大尺寸,按钮仍应固定在底部,滚动视图应占据屏幕的其余部分,此时,如果文本为还更大。

我可以通过编程来完成此操作。这不是什么大问题。我想完全通过 xib 和界面生成器来完成此操作,但我不确定如何使用那里给出的约束选项来解决这个问题。我花了大约 6 个小时尝试不同的事情,但我就是不明白。有什么帮助吗?

swift autolayout interface-builder xib
1个回答
0
投票

这是可以做到的——但是有点复杂。技巧是将滚动视图的高度限制为“内容”视图的高度......具有各种大于/小于/不同的约束优先级和内容拥抱优先级。

写出所有步骤非常困难,所以这是 XIB 的图片:

XIB screen cap

  • 系统黄色是View
  • 粉色是滚动视图
  • 蓝色是“内容”视图
  • 黄色标签
  • 绿色文本视图

这是 XIB 视图类,以及

NibLoadable
协议和扩展:

class TinyTimXIB: UIView, NibLoadable {
    
    @IBOutlet weak var myLabel: UILabel!
    @IBOutlet weak var myTV: UITextView!
    
    var numLines: Int = 0
    var nInc: Int = 2
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupFromNib()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupFromNib()
    }
    
    @IBAction func didTap(_ sender: Any) {
        print("did tap")
        
        numLines += nInc
        if numLines > 15 {
            nInc = -2
        } else if numLines < 4 {
            nInc = 2
        }
        let s = (2...numLines).compactMap( { "Line \($0)" } ).joined(separator: "\n")
        myTV.text = "UITextView\n" + s
        
        guard let btn = sender as? UIButton else { return }
        var cfg = btn.configuration
        var t: String = nInc > 0 ? "Add Lines" : "Remove Lines"
        t += " - Current: \(numLines)"
        cfg?.title = t
        btn.configuration = cfg
    }
}

public protocol NibLoadable {
    static var nibName: String { get }
}

public extension NibLoadable where Self: UIView {
    
    static var nibName: String {
        return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
    }
    
    static var nib: UINib {
        let bundle = Bundle(for: Self.self)
        return UINib(nibName: Self.nibName, bundle: bundle)
    }
    
    func setupFromNib() {
        guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
        addSubview(view)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        view.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        view.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        view.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    }
}

将其添加为视图控制器中的子视图:

View Controller

所有 4 边都有 20 点填充。

每次点击按钮都会添加几行,直到达到 16 条,然后每次点击都会删除几行。一旦我们达到 12 行(在 iPhone 15 Pro 上),滚动视图就会停止增长并变得可滚动:

After first tap

After second tap

with 16 lines


这是 XIB 文件的源代码,以便您可以使用 IB 来检查它:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
        <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>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TinyTimXIB" customModule="scratch202401" customModuleProvider="target">
            <connections>
                <outlet property="myLabel" destination="ngF-8x-hAl" id="SfW-3V-ZsK"/>
                <outlet property="myTV" destination="3e6-OZ-aFR" id="K2o-YH-3In"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="NN7-sN-S8u">
            <rect key="frame" x="0.0" y="0.0" width="432" height="671"/>
            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
            <subviews>
                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Co8-1S-Ok1">
                    <rect key="frame" x="8" y="28" width="416" height="252.5"/>
                    <subviews>
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="k07-XG-JE8" userLabel="CView">
                            <rect key="frame" x="20" y="20" width="376" height="212.5"/>
                            <subviews>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ngF-8x-hAl" userLabel="MyLabel">
                                    <rect key="frame" x="8" y="8" width="360" height="29"/>
                                    <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="24"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" verticalHuggingPriority="1000" scrollEnabled="NO" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3e6-OZ-aFR" userLabel="MyTV">
                                    <rect key="frame" x="8" y="45" width="360" height="159.5"/>
                                    <color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <string key="text">UITextView
Text will be dynamic...</string>
                                    <color key="textColor" systemColor="labelColor"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="40"/>
                                    <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
                                </textView>
                            </subviews>
                            <color key="backgroundColor" red="0.46202266219999999" green="0.83828371759999998" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <constraints>
                                <constraint firstItem="3e6-OZ-aFR" firstAttribute="top" secondItem="ngF-8x-hAl" secondAttribute="bottom" constant="8" id="8q7-Qe-qqo"/>
                                <constraint firstItem="3e6-OZ-aFR" firstAttribute="top" secondItem="ngF-8x-hAl" secondAttribute="bottom" constant="8" id="9xR-by-3kr"/>
                                <constraint firstItem="ngF-8x-hAl" firstAttribute="leading" secondItem="k07-XG-JE8" secondAttribute="leading" constant="8" id="fHY-O5-b28"/>
                                <constraint firstItem="3e6-OZ-aFR" firstAttribute="leading" secondItem="k07-XG-JE8" secondAttribute="leading" constant="8" id="kmr-Sg-lga"/>
                                <constraint firstAttribute="bottom" secondItem="3e6-OZ-aFR" secondAttribute="bottom" constant="8" id="qSL-aL-gs3"/>
                                <constraint firstItem="ngF-8x-hAl" firstAttribute="top" secondItem="k07-XG-JE8" secondAttribute="top" constant="8" id="qh3-II-CX1"/>
                                <constraint firstAttribute="trailing" secondItem="3e6-OZ-aFR" secondAttribute="trailing" constant="8" id="qjo-yL-8ID"/>
                                <constraint firstAttribute="trailing" secondItem="ngF-8x-hAl" secondAttribute="trailing" constant="8" id="sDe-jO-WhS"/>
                            </constraints>
                        </view>
                    </subviews>
                    <color key="backgroundColor" red="1" green="0.79083781379999996" blue="0.99597025539999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    <constraints>
                        <constraint firstAttribute="height" relation="lessThanOrEqual" secondItem="k07-XG-JE8" secondAttribute="height" constant="40" id="5LD-n0-Hd9"/>
                        <constraint firstItem="k07-XG-JE8" firstAttribute="height" secondItem="V8E-tM-mHa" secondAttribute="height" priority="250" constant="-40" id="CFn-Ik-QU0"/>
                        <constraint firstItem="k07-XG-JE8" firstAttribute="bottom" secondItem="jwi-97-yB3" secondAttribute="bottom" constant="-20" id="PWZ-Mc-QtM"/>
                        <constraint firstItem="k07-XG-JE8" firstAttribute="trailing" secondItem="jwi-97-yB3" secondAttribute="trailing" constant="20" id="V1S-dA-dr2"/>
                        <constraint firstItem="k07-XG-JE8" firstAttribute="width" secondItem="V8E-tM-mHa" secondAttribute="width" constant="-40" id="d65-Os-mzF"/>
                        <constraint firstItem="k07-XG-JE8" firstAttribute="top" secondItem="jwi-97-yB3" secondAttribute="top" constant="20" id="gsd-cg-ISa"/>
                        <constraint firstItem="k07-XG-JE8" firstAttribute="leading" secondItem="jwi-97-yB3" secondAttribute="leading" constant="20" id="o4f-sM-k2h"/>
                    </constraints>
                    <viewLayoutGuide key="contentLayoutGuide" id="jwi-97-yB3"/>
                    <viewLayoutGuide key="frameLayoutGuide" id="V8E-tM-mHa"/>
                </scrollView>
                <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0fT-vS-7VT" userLabel="AddLinesBtn">
                    <rect key="frame" x="8" y="613" width="416" height="50"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="50" id="TU4-0f-Y8Z"/>
                    </constraints>
                    <state key="normal" title="Button"/>
                    <buttonConfiguration key="configuration" style="filled" title="Add Lines"/>
                    <connections>
                        <action selector="didTap:" destination="-1" eventType="touchUpInside" id="ToM-EE-Sjz"/>
                    </connections>
                </button>
            </subviews>
            <viewLayoutGuide key="safeArea" id="JWK-TM-5X8"/>
            <color key="backgroundColor" systemColor="systemYellowColor"/>
            <constraints>
                <constraint firstItem="0fT-vS-7VT" firstAttribute="top" secondItem="Co8-1S-Ok1" secondAttribute="bottom" priority="750" constant="8" id="OBz-ja-4yF"/>
                <constraint firstItem="Co8-1S-Ok1" firstAttribute="top" secondItem="JWK-TM-5X8" secondAttribute="top" constant="8" id="ZFJ-F0-dou"/>
                <constraint firstItem="JWK-TM-5X8" firstAttribute="trailing" secondItem="0fT-vS-7VT" secondAttribute="trailing" constant="8" id="cIW-BW-3pC"/>
                <constraint firstItem="0fT-vS-7VT" firstAttribute="top" relation="greaterThanOrEqual" secondItem="Co8-1S-Ok1" secondAttribute="bottom" constant="8" id="fA0-tw-Go1"/>
                <constraint firstItem="JWK-TM-5X8" firstAttribute="bottom" secondItem="0fT-vS-7VT" secondAttribute="bottom" constant="8" id="o37-Gn-NnO"/>
                <constraint firstItem="Co8-1S-Ok1" firstAttribute="leading" secondItem="JWK-TM-5X8" secondAttribute="leading" constant="8" id="oZC-Iy-oyX"/>
                <constraint firstItem="JWK-TM-5X8" firstAttribute="trailing" secondItem="Co8-1S-Ok1" secondAttribute="trailing" constant="8" id="tcy-Gi-3g3"/>
                <constraint firstItem="0fT-vS-7VT" firstAttribute="leading" secondItem="JWK-TM-5X8" secondAttribute="leading" constant="8" id="zW4-Hf-Mdc"/>
            </constraints>
            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
            <point key="canvasLocation" x="283.19999999999999" y="14.842578710644679"/>
        </view>
    </objects>
    <resources>
        <systemColor name="labelColor">
            <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
        <systemColor name="systemYellowColor">
            <color red="1" green="0.80000000000000004" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </systemColor>
    </resources>
</document>
© www.soinside.com 2019 - 2024. All rights reserved.