0

I am fairly used to using SnapKit, but I am not sure how to solve this issue.

This is what my current UI looks like:

enter image description here

To achieve this, I do:

 override func viewDidLoad() {
        super.viewDidLoad()

 regionsPicker.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.height.equalToSuperview() // since we rotate (this is the width)
            make.top.equalTo(regionsLabel.snp.bottom).offset(15)
            make.width.equalTo(100)
        }
 rotationAngle = -90 * (.pi/180)
        regionsPicker.transform = CGAffineTransform(rotationAngle: rotationAngle)
}

As can be seen above, I am trying to align the bottom of my label to the top of my picker view. But since I am rotating my view making the height equal to superview it creates this huge space instead.

I have seen this answer that suggest the use of autolayout for this specific case, and alternatively, I can use collection view as well, but I am curious to know if there is a SnapKit solution for this and of

Thanks for the help.

Matt
  • 674
  • 11
  • 25

1 Answers1

1

The issue lies in this part of the description of transform in Apple's docs: https://developer.apple.com/documentation/uikit/uiview/1622459-transform

In iOS 8.0 and later, the transform property does not affect Auto Layout. Auto layout calculates a view’s alignment rectangle based on its untransformed frame. So, when you change the text of the label, your constraints are related to the untransformed frame.

So, you are setting the height of the pickerView to the height of the view. Then you rotate it, and it appears to look how you want it to look.

If you use Debug View Hierarchy, though, you'll see that the pickerView now extends well past the leading and trailing edges of its superView.

You'll also see the width and height of bounds of the pickerView - 100 x 667 (on an iPhone 8) - which is not what you expected.

This will also present a problem when the view size changes (such as on device rotation).

Here is an example approach:

import UIKit

class ViewController: UIViewController {

    let regionsLabel: UILabel = {
        let v = UILabel()
        v.backgroundColor = .red
        v.text = "Testing"
        return v
    }()

    let regionsPicker: UIPickerView = {
        let v = UIPickerView()
        v.backgroundColor = .green
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .cyan

        // add the label
        view.addSubview(regionsLabel)

        // center label horizontally, 10-pts from view top (safe area)
        regionsLabel.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(10)
        }

        // add the picker view
        view.addSubview(regionsPicker)

        // rotate the picker view
        let rotationAngle: CGFloat = -90 * (.pi/180)
        regionsPicker.transform = CGAffineTransform(rotationAngle: rotationAngle)

    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        regionsPicker.snp.remakeConstraints { (make) in

            // constrain picker view center horizontally
            make.centerX.equalToSuperview()

            // constant of 100 - because it's rotated, set the width
            make.width.equalTo(100)

            // constrain the height to a constant equal to the view width
            make.height.equalTo(view.bounds.width)

            // constrain the centerY to the centerY of the label,
            // plus one-half the label's frame height / 2
            // plus a constant of 65 (half the "height" of the picker view + 15-pts spacing)
            make.centerY.equalTo(regionsLabel.snp.centerY).offset(regionsLabel.frame.height / 2.0 + 65.0)

        }

    }

}

Which results in:

enter image description here enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86