swiftsliderwidthnslayoutconstraintproperty-observer

increase property observer width every time func is called


In my swift code below the scrollview is fixed when I add another box using the propertyObserver I cant increase the scrollview. I want the scrollivew to be increased in size every time a new item is added to the counter. I have added a gif below to show what the problem is. You can see new space is not added to the scrollview.

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
        
    }
}

Solution

  • It's not clear what you're trying to do with your "PropertyObserver" ...

    But, there is a MUCH easier way to accomplish this...

    Here is a simple example:

    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
        }
        
    }