如何使用自动布局根据屏幕尺寸缩放边距?

发布于 2025-01-16 05:30:49 字数 512 浏览 4 评论 0原文

想象一下,我有一个具有特定宽高比约束(这处理高度/底部约束)的 UIImageView,固定到 superview 的顶部,前导,尾随 5pt,在 100pt 中XIB/故事板中的宽度屏幕。这样,如果屏幕尺寸发生变化,图像视图可以相应缩放。

也就是说,在 100pt 宽度的屏幕中,边距间距为 5pt+5pt (10pt),图像占据 90pt(屏幕的 90%)。

不过我希望边距间距也能缩放。

我怎样才能做到这样,在更大的手机上,例如宽度为1000pt(之前的10倍),边距现在相应地为50pt+50pt(100pt),图像占据屏幕的剩余900pt,保留90%? (如果我们使水平约束不同,这可能会更加复杂,例如前导为 15pt,而尾随为 45pt。)

如果我们“正常”执行此操作而不缩放边距 pt,则前导/尾随的约束将为 5pt(在 1000pt 甚至 1000000pt 宽度的手机中总共 10pt!)。这不是我们通常想要的。

我们如何通过自动布局轻松实现这一点?我想到了班级规模,但这不适合我想要做的事情(以满足任何规模的所有设备)。

Imagine I have a UIImageView with a certain aspect ratio constraint (this handles the height/bottom constraint), pinned to superview's top, leading, trailing with 5pt in a 100pt width screen in XIB/storyboard. This way, if the screen size changes, the image view can scale accordingly.

That is 5pt+5pt (10pt) of margin spacing in a 100pt width screen, with image taking up 90pt (90% of the screen).

However I would like the margin spacing to be scaled as well.

How can I make it such that, on a bigger phone, e.g. with width 1000pt (10x previous), the margin will now correspondingly be 50pt+50pt (100pt) with the image taking up the remaining 900pt of the screen, retaining 90%? (This could be further complicated if we are making the horizontal constraints different, e..g. leading be 15pt while the trailing be 45pt.)

If we do it 'normally' without scaling the margin pt, the constraints of leading/trailing would be 5pt (for a total of 10pt in a 1000pt or even a 1000000pt width phone!). This is not what we usually want.

How can we achieve this easily with auto layout? I thought of class sizes but that does not fit what I am trying to do (to cater to all devices of any size).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

撩发小公举 2025-01-23 05:30:49

ASFAIK 没有办法定义相对于另一个视图宽度的前导或尾随约束。

要实现您想要的效果,您可以在 UIImageView 上设置以下约束:

  1. 常量 top 约束
  2. 用于使图像水平居中的 centerX
  3. 约束 常量具有所需宽高比的宽高比约束
  4. 宽度约束,其宽度与UIImageView的超级视图相同,乘数为0.9(90%)

当您执行此操作时,水平边距图像的永远为屏幕尺寸的 10%。

输入图片此处描述

编辑:

当您还需要相对上边距时,您可以将 UIImageView 放入另一个 UIView (具有灰色背景的那个)中,并使用以下约束:

  1. 常量bottom 约束(如果不需要下边距,则为零)
  2. 用于使图像水平居中的 centerX 约束
  3. 与您的图像保持一致的长宽比 约束所需的宽高比
  4. 与 UIImageView 的父视图具有相同宽度且乘数为 0.9 (90%) 的 width 约束
  5. 与 UIImageView 的父视图具有相同高度的 height 约束,并且乘数 0.9(90% 或您想要的任何值)

在此处输入图像描述

如果您希望上边距与水平边距相同,则必须按如下方式计算:verticalMultiplier =水平乘数/(2 *纵横比)

ASFAIK there is no way to define leading or trailing constraints relatively to another view's width.

To achieve what you want you can set the following constraints on the UIImageView:

  1. A constant top constraint
  2. A centerX constraint to center the image horizontally
  3. A constant aspect ratio constraint with your desired aspect ratio
  4. A width constraint with the same width as the UIImageView's superview and a multiplier of 0.9 (90%)

When you do this, the horizontal margins of the image will always be 10% of the screen size.

enter image description here

EDIT:

When you also need a relative top margin you could put the UIImageView into another UIView (the one with the gray background) and use the following constraints:

  1. A constant bottom constraint (zero if you don't want a bottom margin)
  2. A centerX constraint to center the image horizontally
  3. A constant aspect ratio constraint with your desired aspect ratio
  4. A width constraint with the same width as the UIImageView's superview and a multiplier of 0.9 (90%)
  5. A height constraint with the same height as the UIImageView's superview and a multiplier of 0.9 (90% or whatever value you desire)

enter image description here

If you want to have a top margin that is the same as the horizontal margins, you have to calculate it like this: verticalMultiplier = horizontalMultiplier / (2 * aspectRatio)

紧拥背影 2025-01-23 05:30:49

无论是在 Storyboard / IB 中布局还是通过代码完成,最简单的方法可能是使用水平堆栈视图,每侧都有一个(清晰的)“间隔”视图。

不过,您必须提前决定所需的比例。

也就是说,我们认为基于 100-pts 的总宽度,前导空格应为 5-pts ...或 25-pts基于150-pts ...等等。

所以我们的堆栈视图将有3个排列的子视图:

  • “LeftSpacer”
  • imageView(比方说,640:360比例)
  • “RightSpacer”

将 LeftSpacer 的宽度限制为堆栈视图的宽度,乘数为 (左侧空间)/100

将 RightSpacer 的宽度限制为堆栈视图的宽度,乘数为(右侧空间)/100

这里有两个例子。

顶部堆栈视图的左右间隔符均设置为 5/100。底部堆栈视图具有 Left: 5/100Right: 45/100。在两个堆栈视图中,图像视图都设置为 640:360 宽高比(因为这是我方便使用的图像)。

这是堆栈视图 Width: 100 的外观:

在此处输入图像描述

顶部示例 - 两个间隔视图均为 5 点,图像视图为 90 点

底部示例 - 左侧间隔: 5 点,右:45 点,图像视图:50 点

和堆栈视图 宽度:200

在此处输入图像描述

顶部示例 - 两个间隔视图都是10 点,图像视图为 180 点

底部示例 - 左侧间隔:10 点,右侧:90 点,图像视图:100 点

和堆栈视图宽度:300

在此处输入图像描述

顶部示例 - 两个间隔视图均为 15 点,图像视图均为 270 点

底部示例 -左间隔:15 点,右:135 点,图像视图:150 点

这是文档大纲:

在此处输入图像描述

和 Storyboard 源(如果您想检查它):

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina4_0" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
        <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>
        <!--SomeVC-->
        <scene sceneID="YpP-O8-TWi">
            <objects>
                <viewController id="P90-ov-dhs" customClass="SomeVC" customModule="TabBased" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Afn-4E-CtW">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="28" translatesAutoresizingMaskIntoConstraints="NO" id="EZB-9U-TcY">
                                <rect key="frame" x="10" y="20" width="300" height="264.5"/>
                                <subviews>
                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wTh-HR-1cy">
                                        <rect key="frame" x="0.0" y="0.0" width="300" height="152"/>
                                        <subviews>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WVJ-wZ-t9Z" userLabel="LeftSpacerView">
                                                <rect key="frame" x="0.0" y="0.0" width="15" height="152"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="bkg640x360" translatesAutoresizingMaskIntoConstraints="NO" id="39U-sA-bbn">
                                                <rect key="frame" x="15" y="0.0" width="270" height="152"/>
                                                <constraints>
                                                    <constraint firstAttribute="width" secondItem="39U-sA-bbn" secondAttribute="height" multiplier="640:360" id="soT-yc-UP0"/>
                                                </constraints>
                                            </imageView>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tww-ar-yol" userLabel="RightSpacerView">
                                                <rect key="frame" x="285" y="0.0" width="15" height="152"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                        </subviews>
                                        <constraints>
                                            <constraint firstItem="Tww-ar-yol" firstAttribute="width" secondItem="wTh-HR-1cy" secondAttribute="width" multiplier="5/100" id="DLh-N4-vfJ"/>
                                            <constraint firstItem="WVJ-wZ-t9Z" firstAttribute="width" secondItem="wTh-HR-1cy" secondAttribute="width" multiplier="5/100" id="qYi-Rk-ZOI"/>
                                        </constraints>
                                    </stackView>
                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TsK-Kw-YRa">
                                        <rect key="frame" x="0.0" y="180" width="300" height="84.5"/>
                                        <subviews>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iw4-he-3pJ" userLabel="LeftSpacerView">
                                                <rect key="frame" x="0.0" y="0.0" width="15" height="84.5"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="bkg640x360" translatesAutoresizingMaskIntoConstraints="NO" id="P4f-Bc-9F2">
                                                <rect key="frame" x="15" y="0.0" width="150" height="84.5"/>
                                                <constraints>
                                                    <constraint firstAttribute="width" secondItem="P4f-Bc-9F2" secondAttribute="height" multiplier="640:360" id="ZqY-ss-ToB"/>
                                                </constraints>
                                            </imageView>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fs5-7r-dME" userLabel="RightSpacerView">
                                                <rect key="frame" x="165" y="0.0" width="135" height="84.5"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                        </subviews>
                                        <constraints>
                                            <constraint firstItem="iw4-he-3pJ" firstAttribute="width" secondItem="TsK-Kw-YRa" secondAttribute="width" multiplier="5/100" id="D5C-Yo-YOh"/>
                                            <constraint firstItem="Fs5-7r-dME" firstAttribute="width" secondItem="TsK-Kw-YRa" secondAttribute="width" multiplier="45/100" id="ajJ-GY-bZW"/>
                                        </constraints>
                                    </stackView>
                                </subviews>
                                <constraints>
                                    <constraint firstAttribute="width" constant="300" id="Hel-XG-PhB"/>
                                </constraints>
                            </stackView>
                        </subviews>
                        <viewLayoutGuide key="safeArea" id="Ur7-hW-kek"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
                            <constraint firstItem="EZB-9U-TcY" firstAttribute="centerX" secondItem="Afn-4E-CtW" secondAttribute="centerX" id="5lZ-RK-pgy"/>
                            <constraint firstItem="EZB-9U-TcY" firstAttribute="top" secondItem="Ur7-hW-kek" secondAttribute="top" constant="20" id="bg6-Jx-gi9"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" id="ZhN-1l-tl9"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="Rgh-e1-NRf" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-118.125" y="1365"/>
        </scene>
    </scenes>
    <resources>
        <image name="bkg640x360" width="640" height="360"/>
        <systemColor name="systemBackgroundColor">
            <color white="1" 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>

显然,这很容易在代码中复制。

如果出于某种原因,您不想使用堆栈视图,则可以在两个“侧面间隔视图”上使用前导/尾随和比例宽度约束进行本质上相同的操作,或者使其更轻量级,使用 ConstraintLayoutGuide 而不是清晰的视图。


编辑 - 需要更多说明...

首先,我应该通过 ConstraintLayoutGuide 指定我指的是 UILayoutGuide - 哎呀

:(您概述的任务:

如果我的视图宽度为 100 点,我希望子视图的左侧和右侧有 5 点“填充”。但是,随着视图变宽,填充应按比例扩大。因此,如果视图的宽度为 200 磅,则每边的填充量应为 10 磅。

也可以描述为:

我希望每侧都有5%“填充”。

自动布局无法将前导锚点设置为超级视图宽度的百分比。

因此,传统上,我们使用清晰背景的“间隔”视图:

在此处输入图像描述

在 iOS 9 中,Apple 引入了 UILayoutGuide (文档):

概述

使用布局指南来替换您可能创建的占位符视图,以表示用户界面中的视图间空间或封装。

这些不能添加到 Storyboard / IB 中,但可以在代码中使用,其方式与标准 UIView 大致相同。

下面是一个简单的示例,它将“青色”视图和 UILayoutGuide 添加到“容器”视图,为青色视图提供 15% 的“前导空间”:

class LayoutGuideExampleViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let safeG = view.safeAreaLayoutGuide
        
        // create a "container" view
        let cView = UIView()
        cView.translatesAutoresizingMaskIntoConstraints = false
        cView.layer.borderWidth = 1
        cView.layer.borderColor = UIColor.red.cgColor
        
        view.addSubview(cView)
        
        // constraints for the container view
        NSLayoutConstraint.activate([
            cView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 20.0),
            cView.heightAnchor.constraint(equalToConstant: 40.0),
            cView.widthAnchor.constraint(equalToConstant: 100.0),
            cView.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
        ])
        
        // create a "cyan" view
        let cyanView = UIView()
        cyanView.translatesAutoresizingMaskIntoConstraints = false
        cyanView.backgroundColor = .cyan

        // add it to the container
        cView.addSubview(cyanView)

        // constrain the cyan view Top / Bottom / Trailing to the container
        NSLayoutConstraint.activate([
            cyanView.topAnchor.constraint(equalTo: cView.topAnchor),
            cyanView.bottomAnchor.constraint(equalTo: cView.bottomAnchor),
            cyanView.trailingAnchor.constraint(equalTo: cView.trailingAnchor),
        ])
        
        // we want the cyan view's leading-edge to be 15% from the
        //  leading-edge of the container
        // but, we can't do that with a leadingAnchor
        //  so, let's add a UILayoutGuide
        
        // create the guide
        let leftGuide = UILayoutGuide()
        
        // add it to the container view
        cView.addLayoutGuide(leftGuide)
        
        // now, we'll constrain the guide
        NSLayoutConstraint.activate([

            //  Top / Bottom / Leading to the container
            leftGuide.topAnchor.constraint(equalTo: cView.topAnchor),
            leftGuide.bottomAnchor.constraint(equalTo: cView.bottomAnchor),
            leftGuide.leadingAnchor.constraint(equalTo: cView.leadingAnchor),

            //  Width as 15% of the container Width
            leftGuide.widthAnchor.constraint(equalTo: cView.widthAnchor, multiplier: 15.0 / 100.0),
            
            // and cyan view Leading to the guide's Trailing
            cyanView.leadingAnchor.constraint(equalTo: leftGuide.trailingAnchor),
            
        ])
    }
    
}

结果 - 15-pts (15% )对于 100 磅“容器”视图(红色轮廓):

在此处输入图像描述

并且,如果我们将容器宽度更改为 200 点,我们将获得 30 点(15 %) 的前导空格:

在此处输入图像描述

Whether laying this out in Storyboard / IB or doing it via code, probably the easiest way is to use a horizontal stack view, with a (clear) "spacer" view on each side.

What you have to decide in advance, though, is the desired proportion.

That is, we say the leading space should be 5-pts based on a total width of 100-pts ... or 25-pts based on 150-pts ... etc.

So our stack view will have 3 arranged subviews:

  • "LeftSpacer"
  • imageView (with, let's say, a 640:360 ratio)
  • "RightSpacer"

Constrain the Width of the LeftSpacer to the width of the stack view, with a multiplier of (left space)/100.

Constrain the Width of the RightSpacer to the width of the stack view, with a multiplier of (right space)/100.

Here are two examples.

The Top stack view has both left and right spacers set to 5/100. The Bottom stack view has Left: 5/100 and Right: 45/100. In both stack views, the image view is set to 640:360 aspect ratio (because that's the image I had handy).

This is how it looks with stack view Width: 100:

enter image description here

Top example - both spacer views are 5-pts, image view is 90-pts

Bottom example - left spacer: 5-pts, right: 45-pts, image view: 50-pts

and stack view Width: 200:

enter image description here

Top example - both spacer views are 10-pts, image view is 180-pts

Bottom example - left spacer: 10-pts, right: 90-pts, image view: 100-pts

and stack view Width: 300:

enter image description here

Top example - both spacer views are 15-pts, image view is 270-pts

Bottom example - left spacer: 15-pts, right: 135-pts, image view: 150-pts

This is the Document Outline:

enter image description here

and the Storyboard source if you want to inspect it:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
    <device id="retina4_0" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
        <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>
        <!--SomeVC-->
        <scene sceneID="YpP-O8-TWi">
            <objects>
                <viewController id="P90-ov-dhs" customClass="SomeVC" customModule="TabBased" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Afn-4E-CtW">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="28" translatesAutoresizingMaskIntoConstraints="NO" id="EZB-9U-TcY">
                                <rect key="frame" x="10" y="20" width="300" height="264.5"/>
                                <subviews>
                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wTh-HR-1cy">
                                        <rect key="frame" x="0.0" y="0.0" width="300" height="152"/>
                                        <subviews>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WVJ-wZ-t9Z" userLabel="LeftSpacerView">
                                                <rect key="frame" x="0.0" y="0.0" width="15" height="152"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="bkg640x360" translatesAutoresizingMaskIntoConstraints="NO" id="39U-sA-bbn">
                                                <rect key="frame" x="15" y="0.0" width="270" height="152"/>
                                                <constraints>
                                                    <constraint firstAttribute="width" secondItem="39U-sA-bbn" secondAttribute="height" multiplier="640:360" id="soT-yc-UP0"/>
                                                </constraints>
                                            </imageView>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tww-ar-yol" userLabel="RightSpacerView">
                                                <rect key="frame" x="285" y="0.0" width="15" height="152"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                        </subviews>
                                        <constraints>
                                            <constraint firstItem="Tww-ar-yol" firstAttribute="width" secondItem="wTh-HR-1cy" secondAttribute="width" multiplier="5/100" id="DLh-N4-vfJ"/>
                                            <constraint firstItem="WVJ-wZ-t9Z" firstAttribute="width" secondItem="wTh-HR-1cy" secondAttribute="width" multiplier="5/100" id="qYi-Rk-ZOI"/>
                                        </constraints>
                                    </stackView>
                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TsK-Kw-YRa">
                                        <rect key="frame" x="0.0" y="180" width="300" height="84.5"/>
                                        <subviews>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iw4-he-3pJ" userLabel="LeftSpacerView">
                                                <rect key="frame" x="0.0" y="0.0" width="15" height="84.5"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="bkg640x360" translatesAutoresizingMaskIntoConstraints="NO" id="P4f-Bc-9F2">
                                                <rect key="frame" x="15" y="0.0" width="150" height="84.5"/>
                                                <constraints>
                                                    <constraint firstAttribute="width" secondItem="P4f-Bc-9F2" secondAttribute="height" multiplier="640:360" id="ZqY-ss-ToB"/>
                                                </constraints>
                                            </imageView>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Fs5-7r-dME" userLabel="RightSpacerView">
                                                <rect key="frame" x="165" y="0.0" width="135" height="84.5"/>
                                                <color key="backgroundColor" systemColor="systemYellowColor"/>
                                            </view>
                                        </subviews>
                                        <constraints>
                                            <constraint firstItem="iw4-he-3pJ" firstAttribute="width" secondItem="TsK-Kw-YRa" secondAttribute="width" multiplier="5/100" id="D5C-Yo-YOh"/>
                                            <constraint firstItem="Fs5-7r-dME" firstAttribute="width" secondItem="TsK-Kw-YRa" secondAttribute="width" multiplier="45/100" id="ajJ-GY-bZW"/>
                                        </constraints>
                                    </stackView>
                                </subviews>
                                <constraints>
                                    <constraint firstAttribute="width" constant="300" id="Hel-XG-PhB"/>
                                </constraints>
                            </stackView>
                        </subviews>
                        <viewLayoutGuide key="safeArea" id="Ur7-hW-kek"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
                            <constraint firstItem="EZB-9U-TcY" firstAttribute="centerX" secondItem="Afn-4E-CtW" secondAttribute="centerX" id="5lZ-RK-pgy"/>
                            <constraint firstItem="EZB-9U-TcY" firstAttribute="top" secondItem="Ur7-hW-kek" secondAttribute="top" constant="20" id="bg6-Jx-gi9"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" id="ZhN-1l-tl9"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="Rgh-e1-NRf" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-118.125" y="1365"/>
        </scene>
    </scenes>
    <resources>
        <image name="bkg640x360" width="640" height="360"/>
        <systemColor name="systemBackgroundColor">
            <color white="1" 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>

Obviously, that would be straightforward to replicate in code.

If, for some reason, you don't want to use stack views, you could do essentially the same thing with leading/trailing and proportional width constraints on two "side spacer views" or, to make it just a little more light-weight, use ConstraintLayoutGuide instead of a clear view.


Edit - for a little more clarification...

First, I should have specified that by ConstraintLayoutGuide I was referring to UILayoutGuide - whoops :(

The task you've outlined:

If my view is 100-pts wide, I want the subview to have 5-pts "padding" on the left and right. But, as the view gets wider the padding should expand proportionally. So, if the view is 200-pts wide, the padding should be 10-pts on each side.

Could also be described as:

I want 5% "padding" on each side.

Auto-layout does not have a way to set the Leading anchor to a percentage of the superview's width.

So, traditionally, we used clear-background "spacer" views:

enter image description here

With iOS 9, Apple introduced UILayoutGuide (docs):

Overview

Use layout guides to replace the placeholder views you may have created to represent inter-view spaces or encapsulation in your user interface.

These cannot be added in Storyboard / IB, but can be used in code in much the same way as a standard UIView.

Here's a simple example that adds a "cyan" view and a UILayoutGuide to a "container" view, providing 15% of "leading space" to the cyan view:

class LayoutGuideExampleViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let safeG = view.safeAreaLayoutGuide
        
        // create a "container" view
        let cView = UIView()
        cView.translatesAutoresizingMaskIntoConstraints = false
        cView.layer.borderWidth = 1
        cView.layer.borderColor = UIColor.red.cgColor
        
        view.addSubview(cView)
        
        // constraints for the container view
        NSLayoutConstraint.activate([
            cView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 20.0),
            cView.heightAnchor.constraint(equalToConstant: 40.0),
            cView.widthAnchor.constraint(equalToConstant: 100.0),
            cView.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
        ])
        
        // create a "cyan" view
        let cyanView = UIView()
        cyanView.translatesAutoresizingMaskIntoConstraints = false
        cyanView.backgroundColor = .cyan

        // add it to the container
        cView.addSubview(cyanView)

        // constrain the cyan view Top / Bottom / Trailing to the container
        NSLayoutConstraint.activate([
            cyanView.topAnchor.constraint(equalTo: cView.topAnchor),
            cyanView.bottomAnchor.constraint(equalTo: cView.bottomAnchor),
            cyanView.trailingAnchor.constraint(equalTo: cView.trailingAnchor),
        ])
        
        // we want the cyan view's leading-edge to be 15% from the
        //  leading-edge of the container
        // but, we can't do that with a leadingAnchor
        //  so, let's add a UILayoutGuide
        
        // create the guide
        let leftGuide = UILayoutGuide()
        
        // add it to the container view
        cView.addLayoutGuide(leftGuide)
        
        // now, we'll constrain the guide
        NSLayoutConstraint.activate([

            //  Top / Bottom / Leading to the container
            leftGuide.topAnchor.constraint(equalTo: cView.topAnchor),
            leftGuide.bottomAnchor.constraint(equalTo: cView.bottomAnchor),
            leftGuide.leadingAnchor.constraint(equalTo: cView.leadingAnchor),

            //  Width as 15% of the container Width
            leftGuide.widthAnchor.constraint(equalTo: cView.widthAnchor, multiplier: 15.0 / 100.0),
            
            // and cyan view Leading to the guide's Trailing
            cyanView.leadingAnchor.constraint(equalTo: leftGuide.trailingAnchor),
            
        ])
    }
    
}

The result - 15-pts (15%) for a 100-pt "container" view (red outline):

enter image description here

and, if we change the container width to 200-pts, we get 30-pts (15%) of leading space:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文