为什么忽略拥抱优先级?

Why Hugging priority is ignored?

我用 superview 制作了一个文本气泡,它有 2 个动态水平约束:左侧优先级为 1000,右侧优先级为 100。如果气泡是由用户创建的,左约束将具有 100 优先级,而右约束将具有 1000 优先级。

Bubble 内部有带标签的 StackView。堆栈视图被限制为与气泡具有相同的大小。 标签的拥抱和压缩优先级均高于100且低于1000(但上标签优先于下标签)。

想法很简单,优先级为 100 的约束将被打破,气泡将根据需要显示整个文本的大小而变大。

然而它不起作用。气泡比应有的大得多。自动布局似乎忽略了拥抱优先级。

以下是文本“Hhbhj”对气泡的所有约束的描述:

<NSLayoutConstraint:0x283341630 V:|-(10)-[UIStackView:0x113310d90]   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x283341810 H:[UIView:0x113310c20]-(>=16)-|   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x2833414a0 UILabel:0x113311360.height >= 14 priority:999   (active)>
    <NSLayoutConstraint:0x2833416d0 V:|-(6)-[UIView:0x113310c20]   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283341540 H:|-(10)-[UIStackView:0x113310d90]   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x2833415e0 V:[UIStackView:0x113310d90]-(10)-|   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x283340be0 UIImageView:0x113310f20.width == 0 priority:1   (active)>
    <NSLayoutConstraint:0x283341680 H:[UIView:0x113310c20]-(16)-|   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283341360 UILabel:0x1133110f0.height >= 24 priority:999   (active)>
    <NSLayoutConstraint:0x2833417c0 H:|-(16@100)-[UIView:0x113310c20] priority:100   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283341770 H:|-(>=16)-[UIView:0x113310c20]   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283340c80 UIImageView:0x113310f20.height == 183 priority:999   (active)>
    <NSLayoutConstraint:0x283341590 H:[UIStackView:0x113310d90]-(10)-|   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x283341720 V:[UIView:0x113310c20]-(6)-|   (active, names: '|':UITableViewCellContentView:0x113310a90 )>

P.S你也可以在bubble中看到一个imageView。如果气泡中没有图像,请不要担心 imageView 将被隐藏并且约束将被停用。
P.S.S 两个垂直大于约束,只是保证气泡不会变得比他们需要的大。

这是解决这个问题的一种方法...

对于您的标签,请提供顶部(消息)标签:

Content Hugging Priority
    Horizontal: 750
    Vertical: 1000

Content Compression Resistance Priority
    Horizontal: 1000
    Vertical: 750

并给出底部(时间)标签:

Content Hugging Priority
    Horizontal: 251
    Vertical: 1000

Content Compression Resistance Priority
    Horizontal: 1000
    Vertical: 750

这里有两个示例...最上面的一个将“气泡视图”限制在单元格的 Content View 边距。底部的将“气泡视图”的宽度限制为单元格宽度的 80%。

像这样设置你的约束 - ALL with Priority: 1000:

为前导和尾随约束定义 @IBOutlet 变量:

@IBOutlet var sentConstraint: NSLayoutConstraint!
@IBOutlet var receivedConstraint: NSLayoutConstraint!

sentConstraint 连接到 Bubble View.trailing = trailingMargin 约束,并将 receivedConstraint 连接到 Bubble View.leading = leadingMargin 约束。

现在看起来像这样:

当您为单元格设置数据时,激活/停用相应的约束,例如:

// activate / deactivate Trailing / Leading constraints
//  based on sent or received
sentConstraint.isActive = msg.type == .sent
receivedConstraint.isActive = msg.type == .received

>= 前导和尾随约束将防止气泡视图扩展到内容视图框架之外。

这是它的样子:

在消息传递应用程序中,在旁边留下一些“填充”是很常见的。通过将气泡视图的宽度限制为 80%,它可能看起来像这样:

这是我用来生成此布局的代码:

enum MessageType {
    case sent, received
}

struct MessageStruct {
    var imageName: String = ""
    var message: String = ""
    var time: String = ""
    var type: MessageType = .sent
}

class BubbleCell: UITableViewCell {
    
    @IBOutlet var bubbleView: UIView!
    @IBOutlet var myImageView: UIImageView!
    @IBOutlet var messageLabel: UILabel!
    @IBOutlet var timeLabel: UILabel!
    
    @IBOutlet var sentConstraint: NSLayoutConstraint!
    @IBOutlet var receivedConstraint: NSLayoutConstraint!

    func fillData(_ msg: MessageStruct) -> Void {

        // I don't know how you're getting / setting your possible image,
        //  so I'll just set it to hidden for now
        myImageView.isHidden = true

        // set message label text
        messageLabel.text = msg.message
        
        // set time label text, append either sent or rec'd
        //  and set alignment
        timeLabel.text = msg.time + (msg.type == .sent ? " - sent" : " - rec'd")
        timeLabel.textAlignment = msg.type == .sent ? .right : .left
        
        // set colors based on sent or received
        bubbleView.backgroundColor = msg.type == .sent ? .systemGreen : .white
        messageLabel.textColor = msg.type == .sent ? .white : .black
        timeLabel.textColor = msg.type == .sent ? .white : .black
        
        // activate / deactivate Trailing / Leading constraints
        //  based on sent or received
        sentConstraint.isActive = msg.type == .sent
        receivedConstraint.isActive = msg.type == .received
        
        // set corner radii based on sent or received
        bubbleView.layer.cornerRadius = 16
        bubbleView.layer.maskedCorners = msg.type == .sent
            ? [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMinXMaxYCorner]
            : [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMinYCorner]
        
    }
    
}

class MessageTableViewController: UITableViewController {
    
    var myData: [MessageStruct] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var msg: MessageStruct!
        
        msg = MessageStruct(imageName: "",
                            message: "Short message.",
                            time: "09:15",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Short message.",
                            time: "09:15",
                            type: .received)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "This is a longer message.",
                            time: "09:20",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "This is a longer message.",
                            time: "09:20",
                            type: .received)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "This message should be long enough that it needs to wrap in the cell.",
                            time: "09:25",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Another Short message.",
                            time: "09:30",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Another message, long enough that it will need to wrap in the cell.",
                            time: "09:35",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Another message, long enough that it will need to wrap in the cell.",
                            time: "09:35",
                            type: .received)
        myData.append(msg)
        
        tableView.separatorStyle = .none
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // use "bubbleCell" identifier for margin-width limit
        // use "bubble80Cell" identifier for 80% width limit
        let c = tableView.dequeueReusableCell(withIdentifier: "bubbleCell", for: indexPath) as! BubbleCell
        let d = myData[indexPath.row]
        c.fillData(d)
        return c
    }
    
}

这是 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="t48-nh-14V">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Message Table View Controller-->
        <scene sceneID="mMr-vR-h6X">
            <objects>
                <tableViewController id="t48-nh-14V" customClass="MessageTableViewController" customModule="QuickTest" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="BrW-mC-6e6">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <prototypes>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="bubbleCell" rowHeight="260" id="Oi2-T7-oyW" customClass="BubbleCell" customModule="QuickTest" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="28" width="375" height="260"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Oi2-T7-oyW" id="gQY-hx-B2I">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h2Z-Bt-MGu">
                                            <rect key="frame" x="16" y="11" width="343" height="238"/>
                                            <subviews>
                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="wrN-dr-6PW">
                                                    <rect key="frame" x="8" y="12" width="327" height="214"/>
                                                    <subviews>
                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Aio-Ve-8b1">
                                                            <rect key="frame" x="0.0" y="0.0" width="327" height="165.5"/>
                                                        </imageView>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="83w-nH-MFV">
                                                            <rect key="frame" x="0.0" y="171.5" width="327" height="20.5"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="13:50 - sent" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3MO-It-xQw">
                                                            <rect key="frame" x="0.0" y="198" width="327" height="16"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                    </subviews>
                                                </stackView>
                                            </subviews>
                                            <color key="backgroundColor" systemColor="systemGreenColor"/>
                                            <constraints>
                                                <constraint firstItem="wrN-dr-6PW" firstAttribute="top" secondItem="h2Z-Bt-MGu" secondAttribute="top" constant="12" id="61F-T7-VXd"/>
                                                <constraint firstAttribute="trailing" secondItem="wrN-dr-6PW" secondAttribute="trailing" constant="8" id="Aso-zu-ZPc"/>
                                                <constraint firstItem="wrN-dr-6PW" firstAttribute="leading" secondItem="h2Z-Bt-MGu" secondAttribute="leading" constant="8" id="bsG-sY-260"/>
                                                <constraint firstAttribute="bottom" secondItem="wrN-dr-6PW" secondAttribute="bottom" constant="12" id="oAO-Jt-UX3"/>
                                            </constraints>
                                        </view>
                                    </subviews>
                                    <color key="backgroundColor" red="0.897361517" green="0.8974906802" blue="0.89733326440000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <constraints>
                                        <constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="h2Z-Bt-MGu" secondAttribute="trailing" id="6hf-N2-14b"/>
                                        <constraint firstAttribute="bottomMargin" secondItem="h2Z-Bt-MGu" secondAttribute="bottom" id="FxF-PE-6iW"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gQY-hx-B2I" secondAttribute="leadingMargin" id="Wsa-eO-InO"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="top" secondItem="gQY-hx-B2I" secondAttribute="topMargin" id="ZYU-hS-2Pl"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="trailing" secondItem="gQY-hx-B2I" secondAttribute="trailingMargin" id="edX-9l-Ye2"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="leading" secondItem="gQY-hx-B2I" secondAttribute="leadingMargin" id="s0J-rx-Rzx"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="bubbleView" destination="h2Z-Bt-MGu" id="uJ0-t9-ZQ9"/>
                                    <outlet property="messageLabel" destination="83w-nH-MFV" id="pEd-Gg-49x"/>
                                    <outlet property="myImageView" destination="Aio-Ve-8b1" id="qJQ-G9-Qc6"/>
                                    <outlet property="receivedConstraint" destination="s0J-rx-Rzx" id="fCI-9h-2V1"/>
                                    <outlet property="sentConstraint" destination="edX-9l-Ye2" id="KKm-FT-Zcq"/>
                                    <outlet property="timeLabel" destination="3MO-It-xQw" id="bxt-vZ-c2v"/>
                                </connections>
                            </tableViewCell>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="bubble80Cell" rowHeight="260" id="DAc-Zm-a8s" customClass="BubbleCell" customModule="QuickTest" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="288" width="375" height="260"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="DAc-Zm-a8s" id="te5-Rn-aLa">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lFi-s6-a3X">
                                            <rect key="frame" x="16" y="11" width="300" height="238"/>
                                            <subviews>
                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="HX0-dn-sRz">
                                                    <rect key="frame" x="8" y="12" width="284" height="214"/>
                                                    <subviews>
                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Xsw-i1-9mU">
                                                            <rect key="frame" x="0.0" y="0.0" width="284" height="165.5"/>
                                                        </imageView>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Zs-Af-RNQ">
                                                            <rect key="frame" x="0.0" y="171.5" width="284" height="20.5"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="13:50 - sent" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7nV-rU-i4W">
                                                            <rect key="frame" x="0.0" y="198" width="284" height="16"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                    </subviews>
                                                </stackView>
                                            </subviews>
                                            <color key="backgroundColor" systemColor="systemGreenColor"/>
                                            <constraints>
                                                <constraint firstItem="HX0-dn-sRz" firstAttribute="leading" secondItem="lFi-s6-a3X" secondAttribute="leading" constant="8" id="6Kk-f4-tiB"/>
                                                <constraint firstItem="HX0-dn-sRz" firstAttribute="top" secondItem="lFi-s6-a3X" secondAttribute="top" constant="12" id="7H5-6V-Ag0"/>
                                                <constraint firstAttribute="trailing" secondItem="HX0-dn-sRz" secondAttribute="trailing" constant="8" id="Czf-wx-QBQ"/>
                                                <constraint firstAttribute="bottom" secondItem="HX0-dn-sRz" secondAttribute="bottom" constant="12" id="edZ-aP-M1N"/>
                                            </constraints>
                                        </view>
                                    </subviews>
                                    <color key="backgroundColor" red="0.897361517" green="0.8974906802" blue="0.89733326440000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <constraints>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="trailing" secondItem="te5-Rn-aLa" secondAttribute="trailingMargin" id="Ua5-F4-YR5"/>
                                        <constraint firstAttribute="bottomMargin" secondItem="lFi-s6-a3X" secondAttribute="bottom" id="WKr-87-LJK"/>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="leading" secondItem="te5-Rn-aLa" secondAttribute="leadingMargin" id="h4U-ie-xYq"/>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="width" relation="lessThanOrEqual" secondItem="te5-Rn-aLa" secondAttribute="width" multiplier="0.8" id="sKr-Xc-5bn"/>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="top" secondItem="te5-Rn-aLa" secondAttribute="topMargin" id="ueL-NI-qoX"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="bubbleView" destination="lFi-s6-a3X" id="5qj-C0-Uf3"/>
                                    <outlet property="messageLabel" destination="6Zs-Af-RNQ" id="YTU-M9-s7P"/>
                                    <outlet property="myImageView" destination="Xsw-i1-9mU" id="Unr-HS-Iv1"/>
                                    <outlet property="receivedConstraint" destination="h4U-ie-xYq" id="tCy-cc-uHa"/>
                                    <outlet property="sentConstraint" destination="Ua5-F4-YR5" id="Kgg-gY-JCv"/>
                                    <outlet property="timeLabel" destination="7nV-rU-i4W" id="GUX-T1-4Nc"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="t48-nh-14V" id="3oa-OS-rO8"/>
                            <outlet property="delegate" destination="t48-nh-14V" id="7Ua-sV-mwS"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="fpm-tv-1pb"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="2On-8d-2Kp" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-1447.2" y="-749.7751124437782"/>
        </scene>
    </scenes>
    <resources>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
        <systemColor name="systemGreenColor">
            <color red="0.20392156862745098" green="0.7803921568627451" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </systemColor>
    </resources>
</document>

编辑

值得注意——如果我们在 fillData() 中替换这两行:

    sentConstraint.isActive = msg.type == .sent
    receivedConstraint.isActive = msg.type == .received
    

这些:

    sentConstraint.priority = msg.type == .sent ? .defaultHigh : .defaultLow
    receivedConstraint.priority = msg.type == .received ? .defaultHigh : .defaultLow

我们将实现相同的目标。

没有看到您的实际布局(很难破译您发布的“所有约束的描述”),也没有看到您正在使用的代码,很难说为什么它不适合您。