Hi!
I'm trying to port a feature from UIKit to SwiftUI.
Pixel-perfection isn't a hard requirement, but it makes it easier to image-diff the two implementations to find places that need adjustment.
I noticed that when using symbol images, even if the visual size of the opaque part of the symbol is the same, the frame (bounds? margin? extents? padding? Trying to find a word here for the transparent box around the symbol that's UI-framework-agnostic.) is different, which affects apparent whitespace when the symbol is placed in a view.
I created a minimal example in a SwiftUI preview:
struct MyCoolView_Previews: PreviewProvider {
struct UIImageViewWrapper: UIViewRepresentable {
var uiImage: UIImage
func makeUIView(context: Context) -> UIImageView {
let uiImageView = UIImageView()
uiImageView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(
font: UIFont.systemFont(ofSize: 64)
)
uiImageView.tintColor = UIColor.black
return uiImageView
}
func updateUIView(_ uiView: UIImageView, context: Context) {
uiView.image = uiImage
}
}
static var previews: some View {
VStack {
UIImageViewWrapper(uiImage: UIImage(systemName: "exclamationmark.triangle.fill")!)
.background(Color.pink)
.fixedSize()
Image(systemName: "exclamationmark.triangle.fill")
.font(Font.system(size: 64))
.background(Color.pink)
ZStack {
UIImageViewWrapper(uiImage: UIImage(systemName: "exclamationmark.triangle.fill")!)
.background(Color.blue)
.fixedSize()
Image(systemName: "exclamationmark.triangle.fill")
.font(Font.system(size: 64))
.background(Color.pink)
.opacity(0.5)
}
}
}
}
From top to bottom, the screenshot shows the UIKit version, then the SwiftUI version, and finally the two versions overlaid to show where they don't overlap. Note that the blue regions above and below the third item represents where the frame of the UIKit version extends past the frame of the SwiftUI version.
Does anyone know why these are different?
Is there a property that I can set on the SwiftUI version to make it behave like UIKit, or vice-versa?
Thanks!
PS: The difference in frame appears to depend on the specific symbol being used. Here it is for "square.and.arrow.up":