2

My problem - when I add arranged subviews to a stackview programmatically, they just pile up in the upper right-hand corner as shown below. Why aren't they stacking up? I've tried many, many things including using views that have an intrinsic size.

The stackview is called mainStack and comes from a xib. mainStack is a vertical stack with Alignment set to Fill and Distribution set to Fill Equally (see settings at the bottom of this question). It contains one UIView with a blue background. For the sake of this question I have added two views to mainStack using addArrangedSubviews. Here is what I'm getting:

enter image description here

And this is what I would expect:

enter image description here

This is the code for the xib:

class TaskSheet: UIView {

    @IBOutlet var contentView: UIView!
    @IBOutlet weak 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)
        contentView.frame = bounds
        addSubview(contentView)
    }
}

And this is how I'm trying to add views to mainStack:

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(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)
        return sheetArray
    }
}

And, here's the xib showing the stackview settings, just in case...

enter image description here

squarehippo10
  • 1,855
  • 1
  • 15
  • 45
  • This is a little confusing... your `TaskSheet` class for the xib shows an `@IBOutlet var contentView: UIView!` -- but then your code is calling `addSubview(contentView)`? Are you intending to have a much more complex xib? If not, you may save yourself a bit of trouble by using `TaskSheet` as a code-only class instead of a xib. – DonMag Jan 29 '20 at 20:15
  • 1
    If you are using constraints you should set `translateAutoresizingMaskIntoConstraints` property of the view to false – javier rivarola Jan 29 '20 at 20:19
  • You cannot have the distribution to fill equally when you are giving different height constraints to the view, how are they going to be filled equally if you are telling them to be different sizes? – javier rivarola Jan 29 '20 at 20:20
  • Thanks @DonMag - yes, the actual xib has quite a bit more to it. This is just the stripped down version. The root of my problem. – squarehippo10 Jan 29 '20 at 20:35
  • Thanks @javier rivarola - yes, I've tried translatesAutoresizingMaskIntoContraints. (That has been the source of my problems more than once though!) And I do know that I will get a warning if the views are different sizes, but I wanted to show how they are overlapping which would be difficult if they were all the same size. If things were working properly I believe the stackview would simply replace my size constraints. – squarehippo10 Jan 29 '20 at 20:39
  • @squarehippo10 - well, you're missing a couple things... for one, the code you posted never adds an instance of `TaskSheet` to a view, so when I run your code I only see the background from `PDFSheet` – DonMag Jan 29 '20 at 20:44
  • @squarehippo10 - I'm guessing your intent is for the height of `PDFSheet` to be determined by the content? That is, if you want `PDFSheet` to grow in height based on the number (and sizes) of subviews added to `mainStack`? – DonMag Jan 29 '20 at 20:57
  • @ DonMag - my code is only meant to create a PDF which is why it may seem incomplete. You are correct that the end result is for the height of the views to be based on their individual content, but that's a secondary concern at the moment. I just want to know why my views are overlapping instead of stacking up! I'm going to look at your answer more closely now. Thanks! – squarehippo10 Jan 30 '20 at 00:28
  • @squarehippo10 - I've made a couple edits to my answer (it's a bit tough to guess at what you're really trying to do). As to why your original attempts were resulting in overlapping views, well... with the code you provided I can't even replicate that. If you post the full actual code that gave you the overlap result (including your .xib xml source) that will reproduce the result, I'm happy to take a look and see what's going on. – DonMag Jan 30 '20 at 15:16
  • @DonMag - I really appreciate the effort. What I've discovered is that my code does indeed work in a view controller. But when I simply create a view and then save it as a PDF, things fall apart. I have other xibs that are static and work just fine. It's only when I try to add a custom view to a xib that I'm having a problem. I may create a sample project to post on GitHub.Thanks again! – squarehippo10 Jan 30 '20 at 16:53
  • @squarehippo10 - you may have saved some effort by explaining at the beginning exactly what you were doing, and providing a complete example. The problem is likely that you are not allowing auto-layout to fully process your view before writing it to a PDF. Here's a full example -- using the code in my answer, plus a "save to PDF" function: https://github.com/DonMag/StackViewToPDF – DonMag Jan 30 '20 at 18:40
  • @DonMag - setNeedsLayout() and layoutIfNeeded() worked!!!! I see now that I made a few assumptions in my original question that weren't helpful. Thanks for all the effort! – squarehippo10 Jan 31 '20 at 15:47
  • I'm reading the comments stream and feel confused. Is this original question a valid UIStackview layout problem, or only in the context of the PDF conversion? If this is esoteric, the title should convey that. – benc Apr 11 '21 at 00:03

1 Answers1

2

I think I understand what you're going for.

Here's an example...

xib layout (top label, vertical stack view, bottom label):

enter image description here

the stack view's properties:

enter image description here

Code for TaskSheet, PDFSheet and sample view controller:

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
        ])

    }

}

and here's the source of the xib file (to make it easy to check) Edit: whoops, pasted the wrong xml source -- fixed now:

<?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>

Result:

enter image description here


EDIt Slightly modified code to produce the "expected result" image the OP added:

  • removed the labels (I had them there as an example of additional elements)
  • constrained stackView to 0 on all 4 sides
  • changed stackView to Aligment: Fill and 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>

Classes

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),
        ])

    }

}

Result as run on iPad Air 3rd gen (to match the OP's width: 612, height: 792 specification):

enter image description here


Another Edit:

This may be closer to the OP's intent.

  • PDFSheet class is now treated as a "view provider" rather than as a view itself.
  • The first element of the returned array of TaskSheet views (currently containing only one view) will be added as a subview to the viewController's view.

Same .xib file as above.

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)

    }

}

and (visually) the same result. This time, the resulting TaskSheet view is just being added to the viewController's view, without any offset:

enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Your answer is not behaving as the expected result the question is asking. – javier rivarola Jan 30 '20 at 00:39
  • 1
    @javierrivarola - my answer was posted ***before*** the OP edited his question to clarify his "expected result" (worth checking the timestamps). – DonMag Jan 30 '20 at 03:38
  • It doesn’t matter, his issue was that the stackView was behaving in an unexpected behavior, which your answer is also doing, the expected behavior is the one of the stackView, so you don’t need to wait for him to say that, is obvious. – javier rivarola Jan 30 '20 at 12:33
  • @javierrivarola - ok, I'm a bit confused... how is the stackView in my answer behaving in an unexpected manner? The OP's code is setting width and height on the arranged subviews -- so the *expected result* would be different sized subviews. In my example, the yellow subview ***is*** being arranged below the green subview, just as one would expect with a stackView. – DonMag Jan 30 '20 at 13:10
  • You know what the “stack” means in a “stackView”? Is pretty obvious your example is not being stack, they are overlapping, which is not the behavior of a stackView – javier rivarola Jan 30 '20 at 13:13
  • 1
    @javierrivarola - as per the OP's code, the green view is `128 x 240` and the yellow view is `64 x 120` -- they are ***NOT*** overlapping each other. Run my example code and use `Debug View Hierarchy` if you need to confirm it yourself. – DonMag Jan 30 '20 at 13:16
  • Ok this is useless to keep up, just see your result. – javier rivarola Jan 30 '20 at 13:17