iosswiftuikitscreen-rotationstackview

iOS UIKit StackView and handling device rotation properly


I'm working on an app that uses a Scrollview -> StackView -> button, imageview, textview view hierarchy. (I'm building the view programmatically rather than using storyboard. I'm using a scrollview as the top view so it will handle pinch/zoom for me.

If I start the app in portrait mode, things layout like I want. If I then rotate to landscape, the layout does not adjust properly. Same for starting in landscape and then rotating to portrait -- the layout does not adjust correctly.

Here is the layout if I start in portrait. Next image is when I rotate to landscape.

enter image description here

enter image description here

enter image description here

enter image description here

Here is snippets of sample code.

scrollView.frame = view.bounds
scrollView.delegate = self
scrollView.zoomScale = 1.0
scrollView.maximumZoomScale = 5.0
scrollview.minimumZoomScale = 0.5
scrollView.frame = view.bounds

imageView.backgroundColor = .systemGreen
imageView.image = UIImage(systemName: "bell")
imageView.contentMode = .scaleAspectFit

textView.text = "This is a bunch of text blah blah"

stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.addArrangedSubview(textView)
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.spacing = 20

scrollView.addSubview(stackView)
view.addSubview(scrollView)

Any pointers and suggestions would be greatly appreciated.

I'd like to be able to properly handle device rotation. Images show rotation results.


Solution

  • Your code and your goal are a little bit confused, if I understand well you can do it with autoLayout, take a look to my example below:

    class YourViewController: UIViewController {
    
    // Declare your constant
    let scrollView = UIScrollView()
    let imageView = UIImageView()
    let textView = UITextView()
    let label = UILabel()
    let myBGView = UIView()
    let stackView = UIStackView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .red
        setupUI()
        setupConstraints()
    }
    
    // Setup UI elements
    fileprivate func setupUI() {
        myBGView.backgroundColor = .systemYellow
        label.backgroundColor = .systemBlue
        label.text = "Hello World"
        label.textAlignment = .center
        label.font = .systemFont(ofSize: 16, weight: .bold)
        
        textView.backgroundColor = .white
        textView.isUserInteractionEnabled = false
        textView.text = "This is a bunch of text\nMore text on this line\nEven more text"
        
        scrollView.backgroundColor = .red
        scrollView.zoomScale = 1.0
        scrollView.maximumZoomScale = 5.0
        scrollView.minimumZoomScale = 0.5
        
        imageView.backgroundColor = .systemGreen
        imageView.image = UIImage(systemName: "bell")
        imageView.contentMode = .scaleAspectFit
        
        stackView.axis = .vertical
        stackView.distribution = .fillEqually
        stackView.spacing = 20
        stackView.addArrangedSubview(imageView)
        stackView.addArrangedSubview(label)
        stackView.addArrangedSubview(textView)
        
        view.addSubview(scrollView)
        scrollView.addSubview(myBGView)
        myBGView.addSubview(stackView)
    }
    
    //setup constraints
    
    fileprivate func setupConstraints() {
        
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        myBGView.translatesAutoresizingMaskIntoConstraints = false
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        
        myBGView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
        myBGView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        myBGView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
        myBGView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
        myBGView.heightAnchor.constraint(equalToConstant: 299).isActive = true
        
        stackView.topAnchor.constraint(equalTo: myBGView.topAnchor, constant: -1).isActive = true
        stackView.leadingAnchor.constraint(equalTo: myBGView.leadingAnchor).isActive = true
        stackView.trailingAnchor.constraint(equalTo: myBGView.trailingAnchor).isActive = true
        stackView.bottomAnchor.constraint(equalTo: myBGView.bottomAnchor).isActive = true
      }
    }
    

    This is the result:

    enter image description here

    Landscape rotation

    enter image description here

    Simply open a new project and paste the code, if I correctly understand your question this is a good start point for you.