Replacing a style image glitches when using SymbolLayer's `iconSize`
Environment
- Xcode version: 14.3.1
- iOS version: 16.4
- Devices affected: All
- Maps SDK Version: 10.15.1 (also tested with 11 beta)
Observed behavior and steps to reproduce
When loading style images asynchronously and replacing a synchronously returned image there is a visual glitch, if the symbol layer contains an iconSize (either static value or expression).
Once the asynchronously loaded image replaces the existing one it sort of blends with the previous one. This can be observed when double tapping the map (after loading), during the zoom in animation the old image is blended through the new image (see attached video). Once zooming in far enough it works properly.
Note: this behaviour is only present on a UIImage with a scale > 1 (so retina and super retina).
So to summarise:
I've got a SymbolLayer that has an .iconSize expression:
layer.iconSize = .expression(
Expression(.interpolate) {
Expression(.linear)
Expression(.zoom)
3
0.6
4
0.8
6
1.0
}
)
I load images asynchronously on the .styleImageMissing event:
mapView.mapboxMap.onEvery(event: .styleImageMissing) { [weak self] event in
// Provide initial image synchronously
let view = UIView(frame: .init(origin: .zero, size: .init(width: 50, height: 50)))
view.backgroundColor = .green
let image = view.convertToImage()
try! self?.mapView.mapboxMap.style.addImage(image, id: event.payload.id)
// Provide loaded image after 2s delay
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
let view = UIView(frame: .init(origin: .zero, size: .init(width: 50, height: 50)))
view.backgroundColor = .blue
view.layer.cornerRadius = 25
view.clipsToBounds = true
let image = view.convertToImage()
try! self?.mapView.mapboxMap.style.addImage(image, id: event.payload.id)
}
}
When double tapping to zoom in the original image is blended through the new image:
https://github.com/mapbox/mapbox-maps-ios/assets/3206952/668c3aa3-5910-401c-bf59-167577a30fec
When animating the camera manually in code the original image is also blended through the new image:
https://github.com/mapbox/mapbox-maps-ios/assets/3206952/a1233dc9-d158-4f2b-9847-f6fe6384b9ed
Expected behavior
Only the last loaded image should be shown, they should not blend through each other
Notes / preliminary analysis
I think it's all outlined above. The main points are:
- Loading a style image asynchronously
- Having the
.iconSizeproperty set on theSymbolLayer - Having a scale factor of the image thats higher than 1
Additional links and references
Sample project that reproduces this issue: IconBlending.zip