Мне кажется, я понимаю, к чему вы стремитесь.
Вот пример ...
макет xib (верхняя метка, вертикальный вид стека, нижняя метка):
свойства представления стека:
Код для TaskSheet
, PDFSheet
и пример контроллера представления:
class TaskSheet: UIView {
@IBOutlet var contentView: UIView!
@IBOutlet var mainStack: UIStackView!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
let nib = UINib(nibName: "TaskSheet", bundle: nil)
nib.instantiate(withOwner: self, options: nil)
addSubview(contentView)
NSLayoutConstraint.activate([
// constrain contentView on all 4 sides with 8-pts "padding"
contentView.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
contentView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
])
}
}
class PDFSheet: UIView {
var taskSheet: TaskSheet!
var sheetArray = [UIView]()
override init(frame: CGRect) {
super.init(frame: frame)
_ = makeSheet()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_ = makeSheet()
}
func makeSheet() -> [UIView] {
taskSheet = TaskSheet()
let newView1 = UIView(frame: CGRect(x: 0, y: 0, width: 240, height: 128))
newView1.heightAnchor.constraint(equalToConstant: 128).isActive = true
newView1.widthAnchor.constraint(equalToConstant: 240).isActive = true
newView1.backgroundColor = .green
let newView2 = UIView(frame: CGRect(x: 0, y: 0, width: 120, height: 64))
newView2.heightAnchor.constraint(equalToConstant: 64).isActive = true
newView2.widthAnchor.constraint(equalToConstant: 120).isActive = true
newView2.backgroundColor = .yellow
taskSheet.mainStack.addArrangedSubview(newView1)
taskSheet.mainStack.addArrangedSubview(newView2)
sheetArray.append(taskSheet)
addSubview(taskSheet)
taskSheet.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// constrain taskSheet on all 4 sides
taskSheet.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
taskSheet.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
taskSheet.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
taskSheet.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
])
return sheetArray
}
}
class TaskViewController: UIViewController {
var theSheetView: PDFSheet!
override func viewDidLoad() {
super.viewDidLoad()
theSheetView = PDFSheet()
theSheetView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(theSheetView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain the sheet view on all top, leading, trailing with 32-pts "padding"
theSheetView.topAnchor.constraint(equalTo: g.topAnchor, constant: 32.0),
theSheetView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 32.0),
theSheetView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -32.0),
// NO height or bottom constraint
])
}
}
и вот источник файла xib (чтобы его было легко проверить) Редактировать: упс, вставил неправильный xml источник - исправлено :
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<capability name="Safe area layout guides" minToolsVersion="9.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="TaskSheet" customModule="scratchy" customModuleProvider="target">
<connections>
<outlet property="contentView" destination="TFh-sZ-4cx" id="zaP-M3-nAu"/>
<outlet property="mainStack" destination="oGz-Bu-nCT" id="oCb-IB-Q4i"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="315"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TFh-sZ-4cx">
<rect key="frame" x="8" y="8" width="359" height="299"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Top Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jZ3-yl-TaR">
<rect key="frame" x="0.0" y="0.0" width="359" height="21"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="oGz-Bu-nCT">
<rect key="frame" x="0.0" y="21" width="359" height="257"/>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bottom Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8bg-zV-k8Q">
<rect key="frame" x="0.0" y="278" width="359" height="21"/>
<color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.36312681436538696" green="0.3205370306968689" blue="0.87124341726303101" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="oGz-Bu-nCT" firstAttribute="top" secondItem="jZ3-yl-TaR" secondAttribute="bottom" id="3FB-p9-cGU"/>
<constraint firstItem="8bg-zV-k8Q" firstAttribute="leading" secondItem="TFh-sZ-4cx" secondAttribute="leading" id="7bO-hv-chQ"/>
<constraint firstItem="oGz-Bu-nCT" firstAttribute="leading" secondItem="TFh-sZ-4cx" secondAttribute="leading" id="G5h-mz-ag5"/>
<constraint firstItem="jZ3-yl-TaR" firstAttribute="top" secondItem="TFh-sZ-4cx" secondAttribute="top" id="T1H-hj-4jJ"/>
<constraint firstAttribute="bottom" secondItem="8bg-zV-k8Q" secondAttribute="bottom" id="TYr-rY-NAc"/>
<constraint firstAttribute="trailing" secondItem="oGz-Bu-nCT" secondAttribute="trailing" id="VA9-gN-L1a"/>
<constraint firstAttribute="trailing" secondItem="8bg-zV-k8Q" secondAttribute="trailing" id="Vv5-P9-EGo"/>
<constraint firstItem="jZ3-yl-TaR" firstAttribute="leading" secondItem="TFh-sZ-4cx" secondAttribute="leading" id="XZc-QB-dm1"/>
<constraint firstItem="8bg-zV-k8Q" firstAttribute="top" secondItem="oGz-Bu-nCT" secondAttribute="bottom" id="ayn-E8-jo9"/>
<constraint firstAttribute="trailing" secondItem="jZ3-yl-TaR" secondAttribute="trailing" id="v4D-bJ-ltC"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="TFh-sZ-4cx" secondAttribute="trailing" constant="8" id="cgO-BT-ruo"/>
<constraint firstItem="TFh-sZ-4cx" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="8" id="rAA-Vf-F0B"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="TFh-sZ-4cx" secondAttribute="bottom" constant="8" id="rhR-sH-KEq"/>
<constraint firstItem="TFh-sZ-4cx" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="8" id="sag-F8-NuC"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="148" y="49.925037481259373"/>
</view>
</objects>
</document>
Результат:
EDIt слегка изменен код для получения «ожидаемого результата», который добавил ОП:
- удалил метки (у меня они были там в качестве примера дополнительных элементов)
- ограничен stackView для 0 на всех 4 сторонах
- изменено представление стека на
Aligment: Fill
и Distribution: Fill Equally
TaskSheet.xib
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<capability name="Safe area layout guides" minToolsVersion="9.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="TaskSheet" customModule="scratchy" customModuleProvider="target">
<connections>
<outlet property="contentView" destination="TFh-sZ-4cx" id="zaP-M3-nAu"/>
<outlet property="mainStack" destination="oGz-Bu-nCT" id="oCb-IB-Q4i"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="315"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TFh-sZ-4cx">
<rect key="frame" x="8" y="8" width="359" height="299"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="oGz-Bu-nCT">
<rect key="frame" x="0.0" y="0.0" width="359" height="299"/>
</stackView>
</subviews>
<color key="backgroundColor" red="0.36312681436538696" green="0.3205370306968689" blue="0.87124341726303101" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="oGz-Bu-nCT" firstAttribute="leading" secondItem="TFh-sZ-4cx" secondAttribute="leading" id="G5h-mz-ag5"/>
<constraint firstAttribute="bottom" secondItem="oGz-Bu-nCT" secondAttribute="bottom" id="SIv-DX-ZpP"/>
<constraint firstAttribute="trailing" secondItem="oGz-Bu-nCT" secondAttribute="trailing" id="VA9-gN-L1a"/>
<constraint firstItem="oGz-Bu-nCT" firstAttribute="top" secondItem="TFh-sZ-4cx" secondAttribute="top" id="hPW-P3-dsk"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="TFh-sZ-4cx" secondAttribute="trailing" constant="8" id="cgO-BT-ruo"/>
<constraint firstItem="TFh-sZ-4cx" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="8" id="rAA-Vf-F0B"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="TFh-sZ-4cx" secondAttribute="bottom" constant="8" id="rhR-sH-KEq"/>
<constraint firstItem="TFh-sZ-4cx" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="8" id="sag-F8-NuC"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="148" y="49.925037481259373"/>
</view>
</objects>
</document>
Классы
class TaskSheet: UIView {
@IBOutlet var contentView: UIView!
@IBOutlet var mainStack: UIStackView!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
let nib = UINib(nibName: "TaskSheet", bundle: nil)
nib.instantiate(withOwner: self, options: nil)
addSubview(contentView)
NSLayoutConstraint.activate([
// constrain contentView on all 4 sides with 0-pts "padding"
contentView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
contentView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
])
}
}
class PDFSheet: UIView {
var taskSheet: TaskSheet!
var sheetArray = [UIView]()
override init(frame: CGRect) {
super.init(frame: frame)
_ = makeSheet()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_ = makeSheet()
}
func makeSheet() -> [UIView] {
taskSheet = TaskSheet()
let newView1 = UIView()
newView1.backgroundColor = .green
let newView2 = UIView()
newView2.backgroundColor = .yellow
let spacerView = UIView()
spacerView.backgroundColor = .clear
// to get the "expected result" as shown in the OP's image,
// a 3-part stack view with equal heights,
// an easy way is to add a clear "spacer view" as the
// first - "top" - arranged subview
taskSheet.mainStack.addArrangedSubview(spacerView)
taskSheet.mainStack.addArrangedSubview(newView1)
taskSheet.mainStack.addArrangedSubview(newView2)
sheetArray.append(taskSheet)
addSubview(taskSheet)
taskSheet.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// constrain taskSheet on all 4 sides
taskSheet.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
taskSheet.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
taskSheet.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
taskSheet.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
])
return sheetArray
}
}
class TaskViewController: UIViewController {
var theSheetView: PDFSheet!
override func viewDidLoad() {
super.viewDidLoad()
theSheetView = PDFSheet()
theSheetView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(theSheetView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain the sheet view on top and leading at 40-pts (just so it's not flush with top/left of the view)
// with specified width: 612 and height 792
theSheetView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
theSheetView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
theSheetView.widthAnchor.constraint(equalToConstant: 612),
theSheetView.heightAnchor.constraint(equalToConstant: 792),
])
}
}
Результат при запуске на iPad Air 3-го поколения (для ма * Спецификация ОП width: 612, height: 792
):
Другое Редактирование:
Это может быть ближе к цели ОП.
PDFSheet
теперь класс рассматривается как «поставщик представления», а не как само представление. - Первый элемент возвращаемого массива
TaskSheet
представления (в настоящее время содержащие только одно представление) будут добавлены в качестве подпредставления к представлению viewController.
Тот же .xib файл, как указано выше.
class TaskSheet: UIView {
@IBOutlet var contentView: UIView!
@IBOutlet var mainStack: UIStackView!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
let nib = UINib(nibName: "TaskSheet", bundle: nil)
nib.instantiate(withOwner: self, options: nil)
addSubview(contentView)
NSLayoutConstraint.activate([
// constrain contentView on all 4 sides with 0-pts "padding"
contentView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
contentView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
])
}
}
class PDFSheet: UIView {
var taskSheet: TaskSheet!
var sheetArray = [UIView]()
func makeSheet() -> [UIView] {
taskSheet = TaskSheet(frame: CGRect(x: 0, y: 0, width: 612, height: 792))
let newView1 = UIView()
newView1.backgroundColor = .green
let newView2 = UIView()
newView2.backgroundColor = .yellow
let spacerView = UIView()
spacerView.backgroundColor = .clear
// to get the "expected result" as shown in the OP's image,
// a 3-part stack view with equal heights,
// an easy way is to add a clear "spacer view" as the
// first - "top" - arranged subview
taskSheet.mainStack.addArrangedSubview(spacerView)
taskSheet.mainStack.addArrangedSubview(newView1)
taskSheet.mainStack.addArrangedSubview(newView2)
sheetArray.append(taskSheet)
return sheetArray
}
}
class TaskViewController: UIViewController {
var theSheetView: PDFSheet!
override func viewDidLoad() {
super.viewDidLoad()
theSheetView = PDFSheet()
let views: [UIView] = theSheetView.makeSheet()
guard let v = views.first else {
fatalError("PDFSheet failed to create TaskSheet")
}
// note: At this point, the view has not been added to the
// view hierarchy. If you're going to do something with it,
// such as output it to a png or pdf, for example, you need
// to tell auto-layout to do its work
v.setNeedsLayout()
v.layoutIfNeeded()
let s = v.exportAsPdfFromView()
view.addSubview(v)
}
}
и (визуально) тот же результат. На этот раз результирующее представление TaskSheet
просто добавляется в представление viewController без смещения: