Last active
November 16, 2024 19:18
-
-
Save juliensagot/d3c8585bf4929b16facb23f64ec84b41 to your computer and use it in GitHub Desktop.
SwiftUI subpixel alignment stroke animation issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct TestCard: View { | |
private let cornerRadius: CGFloat = 12 | |
@Environment(\.displayScale) private var displayScale | |
@State private var isSelected = false | |
var body: some View { | |
GeometryReader { geometry in | |
Button(action: { | |
isSelected.toggle() | |
}, | |
label: { | |
Rectangle() | |
.foregroundColor(Color.gray) | |
.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) | |
.overlay(selectionOverlayView(in: geometry)) | |
}) | |
} | |
} | |
private func selectionOverlayView(in geometry: GeometryProxy) -> some View { | |
let lineWidth: CGFloat = 2.5 | |
let spacing: CGFloat = 1.5 | |
let bounds = CGRect(origin: .zero, size: geometry.size) | |
let inset = spacing + (lineWidth / 2) | |
let selectionRect = bounds.inset(by: UIEdgeInsets(top: -inset, left: -inset, bottom: -inset, right: -inset)) | |
let offset = (spacing + (lineWidth / 2)).rounded(.up) - (spacing + (lineWidth / 2)) | |
return RoundedRectangle(cornerRadius: cornerRadius + spacing + (lineWidth / 2), style: .continuous) | |
.stroke(Color.red, lineWidth: isSelected ? lineWidth : 0) | |
.animation(.linear(duration: 0.800)) | |
.frame(width: selectionRect.width, height: selectionRect.height, alignment: .center) | |
.offset(x: -offset, y: -offset) // Fixes alignment | |
} | |
} | |
struct TestCard_Previews: PreviewProvider { | |
static var previews: some View { | |
TestCard() | |
.frame(width: 100, height: 135) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment