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