I'm trying to achieve this animation for insertion of an element in a VStack
, all elements move down to create space for the new one and then the new one is inserted from right to left. The code bellow does the insertion as I described, but how to make it work for removal as well, the animation should be similar, the element is completely removed (to the right), then the other elements move up)
struct ContentView: View {
@State var show = false
var body: some View {
VStack {
show ? Rectangle().frame(width: 100, height: 100, alignment: .center)
.animation(Animation.easeIn(duration: 0.5).delay(1))
.transition(.move(edge: .trailing)): nil
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Button("Add") {
show.toggle()
}
Spacer()
}.animation(Animation.easeIn(duration: 0.5))
}
}
I'm not sure what exactly your final outcome should be and my proposed solution is not really "generic", but it should at least give you a starting point.
struct ContentView: View {
@State var show = false
@State var showPlaceholder = false
// The total animation duration will be twice as long as this value
private var animationDuration: TimeInterval = 0.5
var body: some View {
VStack {
ZStack {
if showPlaceholder {
Color.white.opacity(0.0)
.zIndex(1)
.frame(width: 100, height: 100)
}
if show {
Rectangle()
.zIndex(2)
.frame(width: 100, height: 100, alignment: .center)
.animation(Animation.easeIn(duration: animationDuration))
.transition(.move(edge: .trailing))
}
}
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Rectangle().frame(width: 100, height: 100, alignment: .center)
Button("Add") {
if show {
showPlaceholder(for: animationDuration)
show = false
}
else {
showPlaceholder(for: animationDuration) {
show = true
}
}
}
Spacer()
}.animation(Animation.easeIn(duration: animationDuration))
}
private func showPlaceholder(for timeInterval: TimeInterval, completion: (() -> Void)? = nil) {
showPlaceholder = true
Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { (_) in
showPlaceholder = false
completion?()
}
}
}
If you have that many Rectangle()
s, you should use a ForEach
. This will make adding and removing them much easier, because you can just append
and removeLast
to change how many are showing.
Here's what I did:
Rectangle
added
property will control whether the Rectangle
is shown or not RectangleInfo
that will be shown to the userForEach
to loop over the rectangles
transition
, you can use offset
to have more control over the animation.Once the UI is set up, it's time for the animations:
added
to true so it slides in added
to false to slide it outstruct RectangleInfo: Identifiable { /// 1.
let id = UUID()
var added = true /// 2.
}
struct ContentView: View {
@State var rectangles = [ /// 3.
RectangleInfo(),
RectangleInfo(),
RectangleInfo()
]
let animationDuration = 0.5
var body: some View {
VStack {
ForEach(rectangles) { rectangle in /// 4.
Rectangle().frame(width: 100, height: 100, alignment: .center)
.offset(x: rectangle.added ? 0 : 200, y: 0) /// 5.
}
Button("Add") {
rectangles.append(RectangleInfo(added: false)) /// 6.
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
rectangles[rectangles.count - 1].added = true /// 7.
}
}
Button("Remove") {
rectangles[rectangles.count - 1].added = false /// 8.
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
rectangles.removeLast() /// 9.
}
}
Spacer()
}.animation(Animation.easeIn(duration: animationDuration))
}
}
Result:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.