每次调用 func 时增加属性观察器宽度

问题描述

在我下面的 swift 代码中,当我使用 propertyObserver 添加一个框时,滚动视图是固定的 我无法增加滚动视图。我希望每次将新项目添加到计数器时都会增加 scrollivew 的大小。我在下面添加一个 gif 来显示问题所在。你可以看到新的空间没有添加到滚动视图中。

enter image description here

import UIKit

class PropertyObserverExmple {
    var number: Int = 0 {
        willSet(newNumber) {
            print("About to change to \(newNumber)")
        }
        didSet(oldNumber) {
            print("Just changed from \(oldNumber) to \(self.number)")
        }
    }
}

var observer = PropertyObserverExmple()



class SwipeableuIScrollView: UIScrollView {
    
    
    override func touchesShouldCancel(in view: UIView) -> Bool {
        
        if view is UIButton || view is UILabel{
            return true
        }
        
        return touchesShouldCancel(in: view)
    }
    
}
class ViewController: UIViewController {
    
    var scrollView:SwipeableuIScrollView!
    var greenView:UIView!
    
    var addMore:UIButton!
    var leadingAnchor: NSLayoutXAxisAnchor!
    var counter: Int? {
        didSet {
            for i in (oldValue ?? 0)..<(counter ?? 0){
                
                let t_button = UIButton.init(frame: CGRect.zero)
                t_button.translatesAutoresizingMaskIntoConstraints = false
                
                
                t_button.backgroundColor = UIColor.blue
                scrollView.addSubview(t_button)
                
                NSLayoutConstraint.activate([
                    t_button.leadingAnchor.constraint(equalTo: leadingAnchor,constant:5.0),t_button.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor),t_button.heightAnchor.constraint(equalToConstant: 20),t_button.widthAnchor.constraint(equalToConstant: 75.0)
                ])
                
                leadingAnchor = t_button.trailingAnchor
                
                t_button.setTitle("Button \(i)",for: .normal)
                
                
            }
        }
    }
    
    var scrollViewHeightConstraint:NSLayoutConstraint!
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        observer.number = 4
        scrollView = SwipeableuIScrollView.init(frame: CGRect.zero)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        
        greenView = UIView.init(frame: CGRect.zero)
        greenView.translatesAutoresizingMaskIntoConstraints = false
        greenView.backgroundColor = UIColor.green
        
        
        
        addMore = UIButton.init(frame: CGRect.zero)
        addMore.translatesAutoresizingMaskIntoConstraints = false
        addMore.backgroundColor = UIColor.orange
        addMore.setTitle("add",for: .normal)
        
        
        self.view.addSubview(scrollView)
        self.view.addSubview(greenView)
        
        
        self.view.addSubview(addMore)
        
        
        addMore.addTarget(self,action: #selector(increaseC),for: .touchDown)
        
        scrollViewHeightConstraint = NSLayoutConstraint.init(item: scrollView,attribute: .height,relatedBy: NSLayoutConstraint.Relation.equal,toItem: nil,attribute: .notAnAttribute,multiplier: 1.0,constant: 50.0)
        
        NSLayoutConstraint.activate([
            
            addMore.topAnchor.constraint(equalTo: self.view.topAnchor,constant: 50.0),addMore.trailingAnchor.constraint(equalTo: self.view.trailingAnchor,constant: -15.0),addMore.heightAnchor.constraint(equalToConstant: 25.0),addMore.widthAnchor.constraint(equalToConstant: 100.0),scrollView.topAnchor.constraint(equalTo: self.addMore.bottomAnchor,constant: 10.0),scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),scrollViewHeightConstraint,greenView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),greenView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),greenView.topAnchor.constraint(equalTo: self.scrollView.bottomAnchor),greenView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
            
        ])
        
        leadingAnchor  = self.scrollView!.leadingAnchor
        
        counter = 10
        
        self.scrollView.trailingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        
    }
    
    
    
    
    
    
    
    @objc func increaseC(){
        counter! += 1
        
    }
}

解决方法

不清楚你想用你的“PropertyObserver”做什么......

但是,有一个更简单的方法来完成这个......

  • 添加一个 UIStackView 作为滚动视图的子视图
  • 使用该堆栈视图来保存按钮
  • 将堆栈视图限制为滚动视图的 Content Layout Guide

这是一个简单的例子:

class PropertyObserverExmple {
    var number: Int = 0 {
        willSet(newNumber) {
            print("About to change to \(newNumber)")
        }
        didSet(oldNumber) {
            print("Just changed from \(oldNumber) to \(self.number)")
        }
    }
}

var observer = PropertyObserverExmple()

class SwipeableUIScrollView: UIScrollView {
    
    override func touchesShouldCancel(in view: UIView) -> Bool {
        
        if view is UIButton || view is UILabel{
            return true
        }
        
        return touchesShouldCancel(in: view)
    }
    
}

class ScrollButtonsViewController: UIViewController {
    
    // this will hold the buttons
    var stackView: UIStackView!
    
    var scrollView:SwipeableUIScrollView!
    var greenView:UIView!
    
    var addMore:UIButton!
    var leadingAnchor: NSLayoutXAxisAnchor!
    
    var counter: Int? {
        didSet {
            for i in (oldValue ?? 0)..<(counter ?? 0) {
                
                let t_button = UIButton()
                t_button.translatesAutoresizingMaskIntoConstraints = false
                
                t_button.backgroundColor = UIColor.blue
                
                // add it to the stack view,not the scroll view
                //scrollView.addSubview(t_button)
                
                stackView.addArrangedSubview(t_button)
                
                NSLayoutConstraint.activate([
                    t_button.heightAnchor.constraint(equalToConstant: 20),t_button.widthAnchor.constraint(equalToConstant: 75.0)
                ])
                
                t_button.setTitle("Button \(i)",for: .normal)
                
            }
        }
    }
    
    var scrollViewHeightConstraint:NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        observer.number = 4
        scrollView = SwipeableUIScrollView.init(frame: CGRect.zero)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        
        greenView = UIView.init(frame: CGRect.zero)
        greenView.translatesAutoresizingMaskIntoConstraints = false
        greenView.backgroundColor = UIColor.green
        
        addMore = UIButton.init(frame: CGRect.zero)
        addMore.translatesAutoresizingMaskIntoConstraints = false
        addMore.backgroundColor = UIColor.orange
        addMore.setTitle("add",for: .normal)
        addMore.setTitleColor(.white,for: .normal)
        addMore.setTitleColor(.black,for: .highlighted)
        
        self.view.addSubview(scrollView)
        self.view.addSubview(greenView)
        self.view.addSubview(addMore)
        
        addMore.addTarget(self,action: #selector(increaseC),for: .touchDown)

        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        scrollViewHeightConstraint = scrollView.heightAnchor.constraint(equalToConstant: 50.0)
        
        NSLayoutConstraint.activate([
            
            addMore.topAnchor.constraint(equalTo: g.topAnchor,constant: 50.0),addMore.trailingAnchor.constraint(equalTo: g.trailingAnchor,constant: -15.0),addMore.heightAnchor.constraint(equalToConstant: 25.0),addMore.widthAnchor.constraint(equalToConstant: 100.0),scrollView.topAnchor.constraint(equalTo: self.addMore.bottomAnchor,constant: 10.0),scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),scrollViewHeightConstraint,greenView.leadingAnchor.constraint(equalTo: g.leadingAnchor),greenView.trailingAnchor.constraint(equalTo: g.trailingAnchor),greenView.topAnchor.constraint(equalTo: self.scrollView.bottomAnchor),greenView.bottomAnchor.constraint(equalTo: g.bottomAnchor)
            
        ])
        
        stackView = UIStackView()
        stackView.axis = .horizontal    // the default,but just for clarity
        stackView.distribution = .fill  // the default,but just for clarity
        stackView.alignment = .center
        stackView.spacing = 5
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        // add the stack view to the scroll view
        scrollView.addSubview(stackView)
        
        // constrain the stack view
        //  this will ALSO define the "scrollable" area
        NSLayoutConstraint.activate([
            
            // constrain stack view to scroll view's Content Layout Guide
            stackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),stackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),stackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),stackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),// constrain stack view height to scroll view's Frame Layout Guide
            stackView.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),])
        
        counter = 10
        
    }
    
    @objc func increaseC(){
        counter! += 1
    }
    
}