繁体   English   中英

每次调用 uiscrollview 函数时添加 2 个图像视图

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

我的目标下面的 swift 代码是每次添加 2 个图像视图。 你可以在下面的 gif 中只添加一个图像视图。 我只需要添加 2 个图像视图。 图像视图是 lastImage 和 lastImage2。 您只能看到 lastImage 正在显示。 看来我只能在调用 func didclickadd 时添加 1 个 imageview 。

在此处输入图像描述

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

    }

}

情侣笔记...

通过适当的约束设置,自动布局可以自行处理UIScrollView内容大小。 无需设置scrollView.contentSize =...

您有几个向mainView添加子视图(图像视图)的实例,这是滚动视图的子视图,但随后您将该子视图的约束添加到控制器的视图。 确保将元素约束到适当的其他元素。

这是您的代码,带有注释更改:

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

    }

}

使用 Xcode 的“查看调试器”(按钮在下面的屏幕快照中用红色圈出),你会看到发生了什么:

在此处输入图像描述

您的ss视图没有背景颜色。 请注意,当您创建该视图时,您不小心再次重置了imgView背景颜色,而不是设置ss.backgroundColor

修复它,你会看到你的imgViewss

在此处输入图像描述

在尝试诊断此类问题时,视图调试器是您最好的朋友。 现在,很明显,绿色视图可能不是您想要的,但是您现在应该能够看到它并非常容易地诊断该问题。


所有这些都说了,一些观察:

  1. 你让生活变得比你需要的要困难得多。 如果您只是为滚动视图和该滚动视图中的堆栈视图设置约束,那么您只需要添加一个排列的子视图。 例如:

     @objc func didTapButton(_ sender: UIButton) { stackView.addArrangedSubview(randomView()) stackView.addArrangedSubview(randomView()) }

    请注意,一旦设置了堆栈视图和滚动视图(见下文),那么您根本不需要处理这些子视图的contentSize或约束(除了widthAnchorheightAnchor )。 自动布局引擎,结合堆栈视图和滚动视图之间的约束,将为您处理一切。

    因此,一个完整的工作示例:

     class ViewController: UIViewController { let scrollView: UIScrollView = { let scrollView = UIScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() let stackView: UIStackView = { let stackView = UIStackView() stackView.translatesAutoresizingMaskIntoConstraints = false stackView.axis =.vertical stackView.alignment =.center stackView.spacing = 10 return stackView }() let button: UIButton = { let button = UIButton(type: .system) button.translatesAutoresizingMaskIntoConstraints = false button.setTitle("Add", for: .normal) button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() configure() } } // MARK: - Actions extension ViewController { @objc func didTapButton(_ sender: UIButton) { stackView.addArrangedSubview(randomView()) stackView.addArrangedSubview(randomView()) } } // MARK: - Private utility methods private extension ViewController { func configure() { view.addSubview(scrollView) view.addSubview(button) scrollView.addSubview(stackView) NSLayoutConstraint.activate([ // define frame of `scrollView` scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.bottomAnchor.constraint(equalTo: button.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), // define frame of `button` button.centerXAnchor.constraint(equalTo: view.centerXAnchor), button.bottomAnchor.constraint(equalTo: view.bottomAnchor), // define contentSize of `scrollView` based upon size of `stackView` stackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), stackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), stackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), stackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor), // but define width of `stackView` relative to the _main view_ stackView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor) ]) button.setContentHuggingPriority(.required, for: .vertical) } func randomView() -> UIView { let widthRange = view.bounds.width * 0.1... view.bounds.width * 0.9 let heightRange = view.bounds.width * 0.1... view.bounds.width * 0.25 let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ view.widthAnchor.constraint(equalToConstant: .random(in: widthRange)), view.heightAnchor.constraint(equalToConstant: .random(in: heightRange)) ]) view.backgroundColor = UIColor(red: .random(in: 0.25...1), green: .random(in: 0.25...1), blue: .random(in: 0.25...1), alpha: 1) return view } }
  2. 更好的是,我会亲自在 Interface Builder 中设置滚动视图、堆栈视图、按钮和所有相关的约束,然后我的示例中的那个毛茸茸的configure方法就完全消失了。 学习如何以编程方式创建视图很有趣,但在实际项目中,这很少是最高效的方法。 在需要的地方执行程序化视图(例如,通过单击按钮将排列的子视图添加到堆栈视图),否则,对于那些在您第一次运行应用程序时应该存在的视图,Interface Builder 值得考虑。

    例如,它大大减少了上面的代码量,只剩下:

     class ViewController: UIViewController { @IBOutlet weak var scrollView: UIScrollView: @IBOutlet weak var stackView: UIStackView. @IBAction func didTapButton(_ sender. UIButton) { stackView:addArrangedSubview(randomView()) stackView.addArrangedSubview(randomView()) } } // MARK. - Private utility methods private extension ViewController { func randomView() -> UIView {... } }

    显然,习惯在 IB 中设计视图和配置约束需要一段时间,但值得付出努力。 它将我们的代码提炼成最基本的要素。

  3. 在您的代码中,您为这些图像视图设置框架,然后设置translatesAutoresizingMaskIntoConstraints 在这种情况下设置frame绝对没有意义,因为translatesAutoresizingMaskIntoConstraints说“忽略我的frame ,改用约束”。

  4. 我假设您这样做只是为了熟悉滚动视图,但值得注意的是,特别是在添加大量图像视图时,滚动视图本质上是一种低效的方法。

    例如,假设您添加了 100 个图像视图,但一次只能看到 8 个。 您真的想同时保存 memory 中的所有 100 个图像视图吗? 不。

    但是, UITableView ,它是UIScrollView的子类,负责这个。 您最终只会在 memory 中保留当前可见的图像视图。 这是一种更好的方法。

    当您开始使用实际UIImage对象时尤其如此,因为它们需要大量的 memory。 看着大小合理的 PNG/JPG 资产,我们陷入了一种安全感,但是当它们被加载到 memory 时,它们是未压缩的,并且需要不成比例的 memory。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM