View disappears after changing the height with pinch gesture, layer issue

99 views Asked by At

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

There are 0 answers