Question

I have a custom view which has a piano keyboard drawn inside of it. Each key is drawn as a separate call, so that I can only draw keys that need redrawing. The view supports multiple touch, so multiple keys can be held down at once.

Each key is somewhat expensive to draw, so I pass a specific region to setNeedsDisplay whenever a touch is detected on the view in order to avoid re-drawing the entire view (which produces noticeable lag).

In order to handle multiple touches, I iterate over the set of received touches, check if each touch is within one of the keys, and if so, update it and call setNeedsDisplay with the rectangle of that key. In short, setNeedsDisplay is called multiple times in one function, but with a different rect each time.

The behavior that I expected was that drawRect would be invoked multiple times with different dirty regions, however, it seems that if I press the far left and far right keys at the same time, the entire view is redrawn, rather than just the far left and far right keys (as in, all the keys in between are redrawn unnecessarily).

What can I do to achieve what I want? I want to just draw the keys that are touched, not all the keys in between the two dirty keys.

Was it helpful?

Solution

I ran into this and posted my question here.

Curiously, I was also drawing a keyboard (with 88 keys). I never solved it and decided that I would deal with it if it turned out to be a performance problem (don't optimize until you need to etc.). One thing I did do was at start up, rendered that default keyboard into an image and use that as a base, so that I was only drawing the keys which were depressed and not the entire keyboard. Faster to draw an image than all that CGPath stuff.

I was displaying midi notes as they played and performance was fine - so maybe you don't need to be concerned @ this right now.

OTHER TIPS

The system will send you one drawRect: message per turn of the main run loop, regardless of how many times you called setNeedsDisplayInRect:. It passes you a rect that is at least the "union" of all of the dirty rects you passed to setNeedsDisplayInRect:. The system provides no way to find out exactly which rects were passed to setNeedsDisplayInRect:.

You could override setNeedsDisplayInRect: to keep an array of dirty rects (you will find +[NSValue valueWithCGRect:] useful), and clear out the array in drawRect:.

You could create your own setNeedsDisplayForKey: method that keeps an array of dirty keys and calls setNeedsDisplay.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top