0

This is my code. I include every thing to be able to run it. I have two views in a container view. One of them contains buttons. That works fine. The other I draw a grid on it.

When I pinch and scale the size of the grid view to more than 5000 or so, the grid view will disappear. But the button view works fine. I check the size, the view is there, but not showing. It gives me some bugs with layer or something like that.

Can someone please tell me what to do?

class PianoViewController: UIViewController{
    let pianorollcontainer = UIView()
    let topview = UIView()
    let rightScrollView = UIScrollView()
    let rightContainerView = UIView()
    let rightPianoRollView = PianoRollView()
    
    // buttons will go under the PianoRollView
    let rightButtonsView = UIView()
    
    var targetHeight: CGFloat = 1000.0
    let targetwidth: CGFloat = 2000.0
    var firsttouch: CGPoint?
    
    var initalnotwidth: CGFloat = 0
    var noteHeight: CGFloat = 0
   
    let hightconstraints : CGFloat = 1000.0
 
    var buttonHeightConstraints: [NSLayoutConstraint] = []

    // calculate size of notes hight
    func calculateNoteHeight(targetHeight: CGFloat, numN: Int) -> CGFloat {
        let floatNumN: CGFloat = CGFloat(numN)
        
        let noteH1: CGFloat = floor(targetHeight / floatNumN)
        let noteH2: CGFloat = ceil(targetHeight / floatNumN)
        
        let totalHeight1: CGFloat = noteH1 * floatNumN
        let totalHeight2: CGFloat = noteH2 * floatNumN
        
        let diff1: CGFloat = abs(targetHeight - totalHeight1)
        let diff2: CGFloat = abs(targetHeight - totalHeight2)
        
        // if diff1 is less than diff2, use noteH1 else noteH2
        return diff1 < diff2 ? noteH1 : noteH2
    }
    
    // calculate size of notes width
    func calculateNoteWidth(targetWidth: CGFloat, numT: Int) -> CGFloat {
        let floatNumT: CGFloat = CGFloat(numT)
        
        let noteW1: CGFloat = floor(targetWidth / floatNumT)
        let noteW2: CGFloat = ceil(targetWidth / floatNumT)
        
        let totalWidth1: CGFloat = noteW1 * floatNumT
        let totalWidth2: CGFloat = noteW2 * floatNumT
        
        let diff1: CGFloat = abs(targetWidth - totalWidth1)
        let diff2: CGFloat = abs(targetWidth - totalWidth2)
        
        // if diff1 is less than diff2, use noteW1 else noteW2
        return diff1 < diff2 ? noteW1 : noteW2
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.black
        view.addSubview(pianorollcontainer)
        view.addSubview(topview)
        
        pianorollcontainer.backgroundColor = UIColor.white
        topview.backgroundColor = UIColor.gray
        
        noteHeight = calculateNoteHeight(targetHeight: targetHeight, numN: rightPianoRollView.numN)
        initalnotwidth = calculateNoteWidth(targetWidth: targetwidth, numT: rightPianoRollView.numT)
        
        // Add a pinch gesture recognizer to the view
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
        rightPianoRollView.addGestureRecognizer(pinchGesture)
        
        // Add the UIScrollView to the view controller's view
        pianorollcontainer.addSubview(rightScrollView)
       
        // Set the container view as the content view of the scroll view
        rightScrollView.addSubview(rightContainerView)

        // add buttons views amd pianoRoll views to container views
        rightContainerView.addSubview(rightButtonsView)
        rightContainerView.addSubview(rightPianoRollView)
   
        // we will use auto-layout on all views
        topview.translatesAutoresizingMaskIntoConstraints = false
        pianorollcontainer.translatesAutoresizingMaskIntoConstraints = false
      
        rightScrollView.translatesAutoresizingMaskIntoConstraints = false
        
        rightContainerView.translatesAutoresizingMaskIntoConstraints = false
        rightButtonsView.translatesAutoresizingMaskIntoConstraints = false
        rightPianoRollView.translatesAutoresizingMaskIntoConstraints = false
        
        // we (almost) always want to respect the safe area
        let safeG = view.safeAreaLayoutGuide
        
        // we want to constrain scrollView subviews to the scrollView's Content Layout Guide
        let contentG = rightScrollView.contentLayoutGuide
   
        // all the constraint on the main view
        NSLayoutConstraint.activate([
            topview.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            topview.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            topview.topAnchor.constraint(equalTo: safeG.topAnchor),
            topview.bottomAnchor.constraint(equalTo: pianorollcontainer.topAnchor),
            topview.heightAnchor.constraint(equalToConstant: 50),
            
            pianorollcontainer.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            pianorollcontainer.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            pianorollcontainer.topAnchor.constraint(equalTo: topview.bottomAnchor),
            pianorollcontainer.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),
            
            rightScrollView.leadingAnchor.constraint(equalTo: pianorollcontainer.leadingAnchor),
            rightScrollView.trailingAnchor.constraint(equalTo: pianorollcontainer.trailingAnchor),
            rightScrollView.topAnchor.constraint(equalTo: pianorollcontainer.topAnchor),
            rightScrollView.bottomAnchor.constraint(equalTo: pianorollcontainer.bottomAnchor),
      
            rightContainerView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor),
            rightContainerView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor),
            rightContainerView.topAnchor.constraint(equalTo: contentG.topAnchor),
            rightContainerView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor),
            
            // constrain all 4 sides of buttonView to containerView
            rightButtonsView.leadingAnchor.constraint(equalTo: rightContainerView.leadingAnchor),
            rightButtonsView.trailingAnchor.constraint(equalTo: rightContainerView.trailingAnchor),
            rightButtonsView.topAnchor.constraint(equalTo: rightContainerView.topAnchor),
            rightButtonsView.bottomAnchor.constraint(equalTo: rightContainerView.bottomAnchor),
            
            // constrain all 4 sides of pianoRollView to containerView
            rightPianoRollView.leadingAnchor.constraint(equalTo: rightContainerView.leadingAnchor),
            rightPianoRollView.trailingAnchor.constraint(equalTo: rightContainerView.trailingAnchor),
           rightPianoRollView.topAnchor.constraint(equalTo: rightContainerView.topAnchor),
            rightPianoRollView.bottomAnchor.constraint(equalTo: rightContainerView.bottomAnchor),
            // pianoRollView width
            rightPianoRollView.widthAnchor.constraint(equalToConstant: targetwidth),
            ])
        
        // Add buttons to the buttonView
        //  we can constrain them vertically to each other
        var previousButton: UIButton!
        for i in 0..<rightPianoRollView.numN {
            let button = UIButton()
            button.translatesAutoresizingMaskIntoConstraints = false
            rightButtonsView.addSubview(button)
            
            button.leadingAnchor.constraint(equalTo: rightButtonsView.leadingAnchor).isActive = true
            button.trailingAnchor.constraint(equalTo: rightButtonsView.trailingAnchor).isActive = true
            
            let notheightcons = button.heightAnchor.constraint(equalToConstant: noteHeight)
            notheightcons.isActive = true
            buttonHeightConstraints.append(notheightcons)
            
            if previousButton == nil {
                // constrain FIRST button to Top of buttonView
                button.topAnchor.constraint(equalTo: rightButtonsView.topAnchor).isActive = true
            } else {
                // constrain other buttons to Bottom of Previous Button
                button.topAnchor.constraint(equalTo: previousButton.bottomAnchor).isActive = true
            }
            
            // update previousButton to the current button
            previousButton = button
            
            button.setTitle("Button \(i)", for: .normal)
            button.setTitleColor(.black, for: .normal)
            button.backgroundColor = .red
            button.layer.borderWidth = 1.0
            button.layer.borderColor = UIColor.green.cgColor
        }
        
        // constrain bottom of LAST button to bottom of buttonsView
        previousButton.bottomAnchor.constraint(equalTo: rightButtonsView.bottomAnchor).isActive = true
 
        // make sure piano roll has the same height
        rightPianoRollView.noteHeight = noteHeight
        rightPianoRollView.notewidth = initalnotwidth
        
        // Set the background color of the piano roll view to clear
        rightPianoRollView.backgroundColor = UIColor.clear
    
        // for better visual result, disable zoom bouncing
        rightScrollView.bouncesZoom = false
        
        // during development, so we can see the scrollView framing
        rightScrollView.backgroundColor = UIColor.clear
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // set minimum zoom scale
        let minZoomScale = rightScrollView.frame.height / rightPianoRollView.bounds.height
        rightScrollView.minimumZoomScale = minZoomScale
        rightScrollView.maximumZoomScale = minZoomScale
    }
    
    @objc func handlePinch(_ g: UIPinchGestureRecognizer) {
        if g.state == .began || g.state == .changed {
            let newHeightright = targetHeight * g.scale
            let newHeightgo =  max(newHeightright, 100.0)
           
            g.scale = 1.0
            targetHeight = newHeightgo
    
            noteHeight = calculateNoteHeight(targetHeight: newHeightgo, numN: rightPianoRollView.numN)
           
            rightPianoRollView.noteHeight = noteHeight
            rightPianoRollView.setNeedsDisplay()
            
            for (_, constraint) in buttonHeightConstraints.enumerated() {
                constraint.constant = noteHeight
                rightButtonsView.subviews[0].setNeedsLayout()
           
                print("container contain count",rightContainerView.subviews.count)
                print("pianorol height",rightPianoRollView.frame.size.height)
          
                 print("rigth button height",rightButtonsView.frame.size.height)
            }
        }
    }
}

The grid view:

class PianoRollView: UIView {
    var notewidth:CGFloat = 0
    var noteHeight: CGFloat = 0
  
    var numN = 127
    var numT = 128
 
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        // Draw the  grid
        let context = UIGraphicsGetCurrentContext()
        context?.setStrokeColor(UIColor.black.cgColor)
        context?.setLineWidth(1.0)
     
        for i in 1..<numN {
            let y = CGFloat(i) * noteHeight
            context?.move(to: CGPoint(x: 0, y: y))
            context?.addLine(to: CGPoint(x: bounds.width, y: y))
        }
        
        for i in 1..<numT {
            let x = CGFloat(i) * notewidth
            context?.move(to: CGPoint(x: x, y: 0))
            context?.addLine(to: CGPoint(x: x, y: bounds.height))
        }
        
        // Add line to right of grid
        context?.move(to: CGPoint(x: bounds.width, y: 0))
        context?.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
        // Add line to left of grid
        context?.move(to: CGPoint(x: 0, y: 0))
        context?.addLine(to: CGPoint(x: 0, y: bounds.height))
        
        // Add line to top of grid
        context?.move(to: CGPoint(x: 0, y: 0))
        context?.addLine(to: CGPoint(x: bounds.width, y: 0))
        
        // Draw bottom line
        context?.move(to: CGPoint(x: 0, y: bounds.height))
        context?.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
        
        context?.strokePath() 
    }
}
HangarRash
  • 7,314
  • 5
  • 5
  • 32
  • You should see this error in the debug console: `-[ display]: Ignoring bogus layer size (2000.000000, 65532.000000), contentsScale 2.000000, backing store size (4000.000000, 131064.000000)` ... you cannot keep growing a view to an infinite size. – DonMag Apr 13 '23 at 19:26
  • What that means, did I done everything right?but I need my view get bigger,is there any way to get bigger? – user8058965 Apr 13 '23 at 20:17
  • Without knowing exactly what your end goal is, it's very difficult to offer advice. This code is creating a **GIANT** view, and it seems very unlikely that would be usable (memory errors, user would need to scroll forever, etc). Based on some of your other questions, it's very possible that trying to use a scroll view is the wrong approach to begin with. – DonMag Apr 14 '23 at 13:56
  • My end goal is ,to have a Pianorolle like garage band,last time I used,zoom in ,zoom out ,from the scroll view to make my view bigger to be able to edit easily,but that was wrong approach,so now I need to have a view that can be bigger,and smaller with pinch to make it looke like zoom,and the view has two view on it,one grid,one buttons,the height is 1000,allways when it loads ,I have 127 buttons,but it need to get little bit biger than where it fails,and the width get allways a value,it start with 500,then dippend on the lengt of the song,will double,this need to get bigger with pinch, – user8058965 Apr 14 '23 at 17:24
  • You may will need to **draw** all of your elements. Take a look at this as an example: https://stackoverflow.com/a/75899517/6257435 – DonMag Apr 14 '23 at 17:31
  • And all of it of course is in a scroll view,to be able to scroll through the whol view,and as you know from last time ,it’s will be smaller scroll view beside this but just the height will follow the same ,and has the same thing one in,I mean the views,buttons,,So that’s what’s I try do , do you think it’s a wrong approach?please guide me ,I am lust .. – user8058965 Apr 14 '23 at 17:31
  • Your example is ,,using zooming from the scroll view,that’s not my end goal, I already made the one with,scroll view zoom in,out future,but it looks stupid and you can’t really edit,the view need to get bigger then I redraw everything,it looks so good and I can edit so easily,like GarageBand,if you check,but need to get little bite bigger,by the way thanks for taking your time, – user8058965 Apr 14 '23 at 17:46
  • Look at how the drawing is being done... it's using bezier paths and transforming them... the `UIScrollView` is just there for ease -- instead of using pinch/pan gestures. – DonMag Apr 14 '23 at 17:56
  • Still couldn’t make it happen,please if someone can help – user8058965 Apr 21 '23 at 17:33

0 Answers0