I have a RoundedRectangle and I want to make the trim rotate forever and make a nice animation from it.
Tried to make a rotation effect and 3d rotation effect, but it didn't work
@State private var show = false
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 20, style: .continuous)
.foregroundColor(.gray.opacity(0.1))
.frame(width: 195, height: 50)
RoundedRectangle(cornerRadius: 20, style: .continuous)
.trim(from: 0.25, to: 0.5)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round))
.frame(width: show ? 50 : 200, height: show ? 200 : 50)
.rotationEffect(Angle(degrees: show ? 90 : 0))
.animation(.linear.delay(1).repeatForever(autoreverses: true),
value: show)
RoundedRectangle(cornerRadius: 20, style: .continuous)
.trim(from: 0.75, to: 1)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round))
.frame(width: show ? 50 : 200, height: show ? 200 : 50)
.rotationEffect(Angle(degrees: show ? 90 : 0))
.animation(.linear.delay(1).repeatForever(autoreverses: true),
value: show)
Text("title")
.foregroundStyle(LinearGradient(gradient: Gradient(colors: colors),
startPoint: .topLeading,
endPoint: .bottomTrailing))
}
.onAppear {
show.toggle()
}
THis is my code. Made it move, but not the desired way... could be smoother and like two snakes going one after the other one
CodePudding user response:
Animate the changing of the trim offsets. Since it is difficult to animate past the boundaries of 0
and 1
, use .rotation(Angle(degrees: 180))
to always stay within the boundaries of 0
and 1
:
struct ContentView: View {
let colors = [Color.green, Color.blue]
@State private var offset = 0.0
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 20, style: .continuous)
.foregroundColor(.gray.opacity(0.1))
.frame(width: 195, height: 50)
RoundedRectangle(cornerRadius: 20, style: .continuous)
.trim(from: 0.25 offset, to: 0.5 offset)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round))
.frame(width: 195, height: 50)
RoundedRectangle(cornerRadius: 20, style: .continuous)
.trim(from: 0.25 offset, to: 0.5 offset)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round))
.rotation(Angle(degrees: 180))
.frame(width: 195, height: 50)
Text("title")
.foregroundStyle(LinearGradient(gradient: Gradient(colors: colors),
startPoint: .topLeading,
endPoint: .bottomTrailing))
}
.onAppear {
withAnimation(.linear(duration: 0.75).repeatForever(autoreverses: false)) {
offset = 0.5
}
}
}
}
Optimizing the code
Since the two "snakes" are identical except for the 180º rotation, we can code this with a ForEach
:
ForEach([0.0, 180.0], id: \.self) { rotation in
RoundedRectangle(cornerRadius: 20, style: .continuous)
.trim(from: 0.25 offset, to: 0.5 offset)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round))
.rotation(Angle(degrees: rotation))
.frame(width: 195, height: 50)
}