问题描述
我正在尝试使用水平的主UIStackView
和垂直的2个子级UIStackViews
来实现基本布局。
这就是我想要的:
将左侧垂直堆栈的对齐方式设置为fill
会展开黄色标签,但确实会使红色和绿色视图具有相同的宽度。将对齐方式更改为center
可使左侧堆栈不拥抱其子级(就像图片中一样)。
有什么想法应该怎么做?
解决方法
问题是带有UIStackView
的垂直Alignment: Center
没有固有宽度。
要获得所需的布局,您需要将RedView嵌入到透明的UIView
或另一个堆栈视图中,并将其对齐方式设置为Center。
以下是使用堆栈视图的方法,因为与“容器”视图相比,我们需要的约束要少一些:
由于RedView具有宽度和高度限制,因此它将始终为50 x 50
。
“外部”堆栈视图-HorizontalStack
-被限制在所有四个侧面,带有8点“填充”。其属性是:
Axis: Horizontal
Alignment: Center
Distribution: Fill
Spacing: 0
LeftVerticalStack
属性是:
Axis: Vertical
Alignment: Fill
Distribution: Fill
Spacing: 0
RedContainerStack
属性是:
Axis: Vertical
Alignment: Center
Distribution: Fill
Spacing: 0
最后一项必要设置-绿色标签需要拥抱其内容并抵抗压缩:
结果(标签中有几个不同的字符串)
以下是MyCollCell.xib
的来源:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="collection view cell content view" 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"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="Cell" id="p9p-j5-QAK" customClass="MyCollCell" customModule="TableAdd" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="309" height="122"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="7Um-4C-5Kc">
<rect key="frame" x="0.0" y="0.0" width="309" height="122"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="Ezy-2A-s1y" userLabel="HorizontalStack">
<rect key="frame" x="8" y="8" width="293" height="106"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="63E-WY-6Uf" userLabel="LeftVerticalStack">
<rect key="frame" x="0.0" y="18" width="92.5" height="70.5"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="HgJ-l5-geV" userLabel="RedContainerStack">
<rect key="frame" x="0.0" y="0.0" width="92.5" height="50"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="od9-kp-hKh" userLabel="RedView">
<rect key="frame" x="21.5" y="0.0" width="50" height="50"/>
<color key="backgroundColor" red="0.90437477830000002" green="0.1580897272" blue="0.20071530339999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="R5P-yj-c9R"/>
<constraint firstAttribute="width" constant="50" id="zOV-Xo-aVe"/>
</constraints>
</view>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="1000" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="Green Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xzN-ta-GJB">
<rect key="frame" x="0.0" y="50" width="92.5" height="20.5"/>
<color key="backgroundColor" red="0.1673075259" green="0.65853333469999997" blue="0.26840484139999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Yellow Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ReT-76-3Fl">
<rect key="frame" x="92.5" y="43" width="200.5" height="20.5"/>
<color key="backgroundColor" red="0.99657744169999996" green="0.79237681630000001" blue="0.0001898294868" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.46202266219999999" green="0.83828371759999998" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Ezy-2A-s1y" secondAttribute="trailing" constant="8" id="FlO-FQ-5GG"/>
<constraint firstItem="Ezy-2A-s1y" firstAttribute="top" secondItem="7Um-4C-5Kc" secondAttribute="top" constant="8" id="ct6-Mf-RVp"/>
<constraint firstAttribute="bottom" secondItem="Ezy-2A-s1y" secondAttribute="bottom" constant="8" id="dsT-ps-AIz"/>
<constraint firstItem="Ezy-2A-s1y" firstAttribute="leading" secondItem="7Um-4C-5Kc" secondAttribute="leading" constant="8" id="wAj-T5-Vzs"/>
</constraints>
</collectionViewCellContentView>
<size key="customSize" width="309" height="122"/>
<connections>
<outlet property="greenLabel" destination="xzN-ta-GJB" id="1Tu-hu-JOb"/>
<outlet property="yellowLabel" destination="ReT-76-3Fl" id="zTt-ML-CsA"/>
</connections>
<point key="canvasLocation" x="165.94202898550725" y="145.98214285714286"/>
</collectionViewCell>
</objects>
</document>
这是我用来产生上面显示的输出的示例代码:
import UIKit
private let reuseIdentifier = "Cell"
// cell sizing extension and systemLayoutSizeFitting implementation
// is not mine,but can be found here:
// https://www.robertpieta.com/autosizing-full-width-cells/
extension UICollectionView {
var widestCellWidth: CGFloat {
let insets = contentInset.left + contentInset.right
return bounds.width - insets
}
}
class MyCollCell: UICollectionViewCell {
@IBOutlet var greenLabel: UILabel!
@IBOutlet var yellowLabel: UILabel!
override func systemLayoutSizeFitting(
_ targetSize: CGSize,withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority,verticalFittingPriority: UILayoutPriority) -> CGSize {
// Replace the height in the target size to
// allow the cell to flexibly compute its height
var targetSize = targetSize
targetSize.height = CGFloat.greatestFiniteMagnitude
// The .required horizontal fitting priority means
// the desired cell width (targetSize.width) will be
// preserved. However,the vertical fitting priority is
// .fittingSizeLevel meaning the cell will find the
// height that best fits the content
let size = super.systemLayoutSizeFitting(
targetSize,withHorizontalFittingPriority: .required,verticalFittingPriority: .fittingSizeLevel
)
return size
}
}
class MyCollectionViewController: UICollectionViewController {
let myData: [[String]] = [
["Green Label","Yellow Label"],["G",["Longer Green Label",["Green Label","Yellow Label with too much text to fit here."],"Yellow Label with .numberOfLines set to 0 will wrap when there's too much text."],]
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
self.collectionView.register(UINib(nibName: "MyCollCell",bundle: nil),forCellWithReuseIdentifier: reuseIdentifier)
let layout = collectionView.collectionViewLayout
if let flowLayout = layout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = CGSize(
width: collectionView.widestCellWidth,// Make the height a reasonable estimate to
// ensure the scroll bar remains smooth
height: 100
)
}
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
return myData.count
}
override func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,for: indexPath) as! MyCollCell
cell.greenLabel.text = myData[indexPath.row][0]
cell.yellowLabel.text = myData[indexPath.row][1]
cell.yellowLabel.numberOfLines = indexPath.item == 4 ? 0 : 1
return cell
}
}
,
参考我在下面上传的照片,我在 UIView (紫色)中放置了左垂直堆叠视图,然后将其嵌入在带有黄色标签的水平堆栈视图中。我将分布设置为等间距,且间距为0 ,这样就不会有间距。
我将左垂直堆栈视图的所有边的约束设置为0(这样,左垂直堆栈视图将采用整个紫色的UIView)。还将 alignment (对齐方式)设置为 center (居中),以使子视图在水平方向居中。
在左垂直堆栈视图内部,我为尾随,前导和底部添加了约束0 ,以便使左堆栈视图与最大的子项(绿色标签)一样“宽”。我将标签文本更改为居中,以使文本位于中心。
希望这能回答您的问题!