SwiftUI: показывать определенные виды с задержкой анимации

#swiftui

#swiftui

Вопрос:

Я пытаюсь добиться следующей анимации: когда я нажимаю на прямоугольник, прямоугольник должен быть расширен на всю ширину с помощью кнопки закрытия в углу, а под этим прямоугольником должен появиться ScrollView. Пока это работает без каких-либо проблем. Теперь я хотел бы отобразить ScrollView немного позже, чем расширенный прямоугольник. Итак, когда я нажимаю на прямоугольник: сначала должен появиться расширенный прямоугольник с кнопкой закрытия, а через 3 секунды — ScrollView.

 struct Playground: View {
    @Namespace var namespace
    @State var show = false
    private let gridItems = [GridItem(.flexible())]
    
    
    var body: some View {
        
        if show {
            VStack{
                ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)){
                    Rectangle()
                        .matchedGeometryEffect(id: "A", in: namespace, isSource: show)
                        .frame(height: 300)
                        .frame(maxWidth: .infinity)
                    
                    Image(systemName: "xmark")
                        .font(.system(size: 25))
                        .foregroundColor(.white)
                        .background(Color.red)
                        .padding(20)
                        .onTapGesture {
                            withAnimation(.spring()){
                                self.show = false
                            }
                        }
                }
                // SHOW THIS SCROLLVIEW 3 SECONDS LATER
                ScrollView{
                    LazyVGrid(columns: gridItems){
                        ForEach(0..<10){ cell in
                            Text("(cell)")
                        }
                    }
                }
                .animation(Animation.spring().delay(3)) // doesn't work!

            }
        } else {
            Rectangle()
                .matchedGeometryEffect(id: "A", in: namespace, isSource: !show)
                .frame(width: 100, height: 100)
                .onTapGesture {
                    withAnimation(.spring()){
                        self.show = true
                    }
                }
        }
    }
}
 

Ответ №1:

Нам нужно сделать разделенную анимацию (и связанное состояние) для ScrollView в этом сценарии.

Вот возможный подход. Протестировано с Xcode 12.1 / iOS 14.1

ДЕМОНСТРАЦИЯ

 struct Playground: View {
    @Namespace var namespace
    @State var show = false
    private let gridItems = [GridItem(.flexible())]
    
    @State private var showItems = false
    
    var body: some View {
        
        if show {
            VStack{
                ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)){
                    Rectangle()
                        .matchedGeometryEffect(id: "A", in: namespace, isSource: show)
                        .frame(height: 300)
                        .frame(maxWidth: .infinity)
                    
                    Image(systemName: "xmark")
                        .font(.system(size: 25))
                        .foregroundColor(.white)
                        .background(Color.red)
                        .padding(20)
                        .onTapGesture {
                            withAnimation(.spring()){
                                self.show = false
                            }
                        }
                }
                
                VStack {
                    if showItems {
                        ScrollView{
                            LazyVGrid(columns: gridItems){
                                ForEach(0..<10){ cell in
                                    Text("(cell)")
                                }
                            }
                        }
                    } else {
                        Spacer()
                    }
                }
                .onAppear { showItems = true }
                .onDisappear { showItems = false }
                .animation(Animation.spring().delay(3), value: showItems)
            }
        } else {
            Rectangle()
                .matchedGeometryEffect(id: "A", in: namespace, isSource: !show)
                .frame(width: 100, height: 100)
                .onTapGesture {
                    withAnimation(.spring()){
                        self.show = true
                    }
                }
        }
    }
}
 

резервное копирование