Search code examples
swiftuiscrollviewimageviewaddsubview

add 2 image views to a uiscrollview func every time it is called


My swift code below goal is to add 2 image views every time. Ass you can in the gif below only one image view is being added. I just need to add 2 image views. The image views are lastImage and lastImage2. you can see only lastImage is being shown. It seems I can only add 1 imageview when func didclickadd is called.

enter image description here

import UIKit

class ViewController: UIViewController {

    fileprivate var  lastImage:UIImageView?
    fileprivate var  lastImage2:UIImageView?

    fileprivate var mainViewBootom:NSLayoutConstraint?


    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        setupVIew()
    }

    override func viewDidAppear(_ animated: Bool) {
        scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
        view.layoutIfNeeded()
    }

    //MARK: Components
    let scrollView:UIScrollView = {
        let sv = UIScrollView(frame: .zero)
        return sv
    }()

    let mainView:UIView = {
        let uv = UIView()
        uv.backgroundColor = .white
        return uv
    }()

    let btnAdd:UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Add", for: .normal)
        return btn
    }()



    let textField:UITextField = {
        let jake = UITextField()
        return jake

    }()

    //MARK: Setup UI
    func setupVIew() {
        view.addSubview(scrollView)
        view.addSubview(btnAdd)
        view.addSubview(textField)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        btnAdd.translatesAutoresizingMaskIntoConstraints = false
        textField.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([




            btnAdd.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            btnAdd.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
            btnAdd.widthAnchor.constraint(equalToConstant: 100),
            btnAdd.heightAnchor.constraint(equalToConstant: 45),


            //
            textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            textField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 25),
            textField.widthAnchor.constraint(equalToConstant: 100),
            textField.heightAnchor.constraint(equalToConstant: 45),
            //



            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            scrollView.bottomAnchor.constraint(equalTo: btnAdd.topAnchor , constant: -12),
        ])
        btnAdd.addTarget(self, action: #selector(didClickedAdd), for: .touchUpInside)

        scrollView.addSubview(mainView)
        mainView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            mainView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            mainView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            mainView.topAnchor.constraint(equalTo: scrollView.topAnchor),
        ])

        let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
        imgView.backgroundColor  = .red
        mainView.addSubview(imgView)


        let samsam = UIImageView(frame: CGRect(x: 0, y: 200, width: 40, height: 100))
        samsam.backgroundColor  = .blue
        mainView.addSubview(samsam)




        imgView.translatesAutoresizingMaskIntoConstraints = false
        imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        imgView.widthAnchor.constraint(equalToConstant: 150).isActive = true
        imgView.heightAnchor.constraint(equalToConstant: 100).isActive = true


        samsam.translatesAutoresizingMaskIntoConstraints = false
        samsam.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        samsam.topAnchor.constraint(equalTo: imgView.bottomAnchor).isActive = true
        samsam.widthAnchor.constraint(equalToConstant: 75).isActive = true
        samsam.heightAnchor.constraint(equalToConstant: 100).isActive = true



        if lastImage != nil {
            imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 20).isActive = true
        }else{
            imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 12).isActive = true
        }
        lastImage = samsam
        mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 12)
        mainViewBootom!.isActive = true
    }

    @objc func didClickedAdd(){
        let imgView = UIImageView(frame: CGRect(x: 20, y: 0, width: 30, height: 20))
        imgView.backgroundColor  = .orange
        mainView.addSubview(imgView)

        let ss = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 50))
        imgView.backgroundColor  = .green
        mainView.addSubview(ss)


        imgView.translatesAutoresizingMaskIntoConstraints = false
        imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        imgView.widthAnchor.constraint(equalToConstant: 40).isActive = true
        imgView.heightAnchor.constraint(equalToConstant: 60).isActive = true


        ss.translatesAutoresizingMaskIntoConstraints = false
        ss.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = false
        ss.widthAnchor.constraint(equalToConstant: 80).isActive = true
        ss.heightAnchor.constraint(equalToConstant: 90).isActive = true

        if lastImage != nil {

            ss.topAnchor.constraint(equalTo: imgView.topAnchor , constant: 20).isActive = true

            imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 50).isActive = true



        }else{
            imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 10).isActive = true
            ss.bottomAnchor.constraint(equalTo: imgView.bottomAnchor , constant: 25).isActive = true


        }


        lastImage = imgView
        lastImage2 = ss
        mainView.removeConstraint(mainViewBootom!)


        mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage2!.bottomAnchor , constant: 40)




        mainViewBootom!.isActive = true
        view.layoutIfNeeded()

        scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
        view.layoutIfNeeded()

    }

}

Solution

  • Couple notes...

    With proper constraint setup, auto-layout handles the UIScrollView content size all by itself. No need to ever set scrollView.contentSize = ...

    You have several instances of adding a subview (image view) to your mainView, which is a subview of your scroll view, but then you add constraints from that subview to your controller's view. Make sure you are constraining elements to the proper other elements.

    Here's your code, with commented changes:

    class BenViewController: UIViewController {
    
        fileprivate var  lastImage:UIImageView?
    
    // 1) don't need this
    //  fileprivate var  lastImage2:UIImageView?
    
        fileprivate var mainViewBootom:NSLayoutConstraint?
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .white
            setupVIew()
        }
    
    // 2) don't need this
    //  override func viewDidAppear(_ animated: Bool) {
    //      scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
    //      view.layoutIfNeeded()
    //  }
    
        //MARK: Components
        let scrollView:UIScrollView = {
            let sv = UIScrollView(frame: .zero)
            return sv
        }()
    
        let mainView:UIView = {
            let uv = UIView()
            uv.backgroundColor = .white
            return uv
        }()
    
        let btnAdd:UIButton = {
            let btn = UIButton(type: .system)
            btn.setTitle("Add", for: .normal)
            return btn
        }()
    
    
    
        let textField:UITextField = {
            let jake = UITextField()
            return jake
    
        }()
    
        //MARK: Setup UI
        func setupVIew() {
            view.addSubview(scrollView)
            view.addSubview(btnAdd)
            view.addSubview(textField)
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            btnAdd.translatesAutoresizingMaskIntoConstraints = false
            textField.translatesAutoresizingMaskIntoConstraints = false
    
            NSLayoutConstraint.activate([
    
    
    
    
                btnAdd.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                btnAdd.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
                btnAdd.widthAnchor.constraint(equalToConstant: 100),
                btnAdd.heightAnchor.constraint(equalToConstant: 45),
    
    
                //
                textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                textField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 25),
                textField.widthAnchor.constraint(equalToConstant: 100),
                textField.heightAnchor.constraint(equalToConstant: 45),
                //
    
    
    
                scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                scrollView.bottomAnchor.constraint(equalTo: btnAdd.topAnchor , constant: -12),
            ])
            btnAdd.addTarget(self, action: #selector(didClickedAdd), for: .touchUpInside)
    
            scrollView.addSubview(mainView)
            mainView.translatesAutoresizingMaskIntoConstraints = false
    
    // 3) change this:
    //      NSLayoutConstraint.activate([
    //          mainView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    //          mainView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
    //          mainView.topAnchor.constraint(equalTo: scrollView.topAnchor),
    //      ])
    //
    
    // to this
            NSLayoutConstraint.activate([
                mainView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
                mainView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
                mainView.topAnchor.constraint(equalTo: scrollView.topAnchor),
                mainView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
                mainView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
            ])
    // end of change 3)
    
            let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
            imgView.backgroundColor  = .red
            mainView.addSubview(imgView)
    
    
            let samsam = UIImageView(frame: CGRect(x: 0, y: 200, width: 40, height: 100))
            samsam.backgroundColor  = .blue
            mainView.addSubview(samsam)
    
    
            imgView.translatesAutoresizingMaskIntoConstraints = false
    
    // 4) change view.centerXAnchor to mainView.centerXAnchor
    //      imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            imgView.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
    
            imgView.widthAnchor.constraint(equalToConstant: 150).isActive = true
            imgView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    
    
            samsam.translatesAutoresizingMaskIntoConstraints = false
    
    // 5) change view.centerXAnchor to mainView.centerXAnchor
    //      samsam.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            samsam.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
    
            samsam.topAnchor.constraint(equalTo: imgView.bottomAnchor).isActive = true
            samsam.widthAnchor.constraint(equalToConstant: 75).isActive = true
            samsam.heightAnchor.constraint(equalToConstant: 100).isActive = true
    
    
    
            if lastImage != nil {
                imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 20).isActive = true
            }else{
                imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 12).isActive = true
            }
            lastImage = samsam
            mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 12)
            mainViewBootom!.isActive = true
        }
    
        @objc func didClickedAdd(){
            let imgView = UIImageView(frame: CGRect(x: 20, y: 0, width: 30, height: 20))
            imgView.backgroundColor  = .orange
            mainView.addSubview(imgView)
    
            let ss = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 50))
    
    // 6) typo or copy/paste mistake
    //      imgView.backgroundColor  = .green
            ss.backgroundColor  = .green
    
            mainView.addSubview(ss)
    
    
            imgView.translatesAutoresizingMaskIntoConstraints = false
    
    // 7) change view.centerXAnchor to mainView.centerXAnchor
    //      imgView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            imgView.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
    
            imgView.widthAnchor.constraint(equalToConstant: 40).isActive = true
            imgView.heightAnchor.constraint(equalToConstant: 60).isActive = true
    
    
            ss.translatesAutoresizingMaskIntoConstraints = false
    
    // 8) change view.leadingAnchor to mainView.leadingAnchor
    //      ss.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = false
            ss.leadingAnchor.constraint(equalTo: mainView.leadingAnchor).isActive = false
    
            ss.widthAnchor.constraint(equalToConstant: 80).isActive = true
            ss.heightAnchor.constraint(equalToConstant: 90).isActive = true
    
    // 9) always need to do this ... but did you mean imgView.bottomAnchor?
            ss.topAnchor.constraint(equalTo: imgView.topAnchor , constant: 20).isActive = true
    
            if lastImage != nil {
    
                // 9a) instead of only here
                //ss.topAnchor.constraint(equalTo: imgView.topAnchor , constant: 20).isActive = true
    
                imgView.topAnchor.constraint(equalTo: lastImage!.bottomAnchor , constant: 50).isActive = true
    
            }else{
    
                imgView.topAnchor.constraint(equalTo: mainView.topAnchor , constant: 10).isActive = true
    
            }
    
    // 10) always need to do this
            // deactivate bottom constraint
            mainViewBootom?.isActive = false
            lastImage = ss
            mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage!.bottomAnchor, constant: 40)
            mainViewBootom?.isActive = true
    
    // 11) don't need any of this
    //      lastImage = imgView
    //      lastImage2 = ss
    //      mainView.removeConstraint(mainViewBootom!)
    //
    //
    //      mainViewBootom = mainView.bottomAnchor.constraint(equalTo: lastImage2!.bottomAnchor , constant: 40)
    //
    //
    //
    //
    //      mainViewBootom!.isActive = true
    //      view.layoutIfNeeded()
    //
    //      scrollView.contentSize = CGSize(width: view.frame.width, height: mainView.frame.height)
    //      view.layoutIfNeeded()
    
        }
    
    }