I have not yet checked if the "redraws entire contents instead of specified rect" issue is still occurring.
However, the "flashes on redraw" issue is still occurring with CATiledLayer in Xcode 26.6.
The flash occurs even when returning 0 from CATiledLayer.fadeDuration().
It seems that each sublayer/tile of the CATiledLayer simply releases/erases its already-drawn contents before drawing the new contents.
It would be nice to have the option to replace the existing drawing without erasing it first.
This solution from @mgalijot:
[quote='786127021, mgalijot, /thread/786127, /profile/mgalijot']
I have, however, found one interesting thing which seems to work so far: before calling setNeedsDisplayInRect (or just setNeedsDisplay, as they behave the same for CATiledLayer in my testing), cache the current layer's contents, and after calling setNeedsDisplay (or setNeedsDisplayInRect), restore the contents back to the layer. This prevents flashing and preserves any tiles that were drawn at the time of the re-draw.
let c = tiledLayer.contents tiledLayer.setNeedsDisplay(tileRect) tiledLayer.contents = c
[/quote]
does fix the flash. Could an Apple engineer comment whether or not this is a valid workaround?
Here's the relevant code I'm currently using (Swift 6):
CATiledLayer subclass
nonisolated final class NoFade_CATiledLayer: CATiledLayer {
override class func fadeDuration() -> CFTimeInterval {
0
}
}
UIView layerClass
override class var layerClass: AnyClass {
NoFade_CATiledLayer.self
}
UIView draw(_:)
/* This method must be marked "nonisolated" when it is called by
"CATiledLayer" or one of its sublayers. Otherwise, the app crashes. */
nonisolated override func draw(_ rect: CGRect) {
guard let cgContext = UIGraphicsGetCurrentContext() else {
return
}
let cgPaths = cgPaths_Mutex.withLock { $0 }
let fillColor = CGColor(
srgbRed: 0.5,
green: 0.5,
blue: 0.5,
alpha: 1
)
for cgPath in cgPaths {
cgContext.addPath(cgPath)
cgContext.setFillColor(fillColor)
cgContext.fillPath()
}
}
Calling setNeedsDisplay()
private func onChange_cgPaths(newPaths: [CGPath]) {
cgPaths_Mutex.withLock { (cgPaths: inout [CGPath]) -> Void in
cgPaths = newPaths
}
setNeedsDisplay()
}
Topic:
UI Frameworks
SubTopic:
General
Tags: