如何在Swift UI中不使用ForEach循环来循环抽认卡视图的ZStack?

46qrfjad  于 2023-03-16  发布在  Swift
关注(0)|答案(1)|浏览(98)

大家好!我想建立一个视图与ZStack的卡获得信息从一个数组。卡必须刷卡向左和向右的。手势修饰符,没有任何其他按钮。我想要的是,当当前卡显示,下一张卡是看不到的。而当当前卡离开,下一张卡自动显示。
长话短说,我想让刷卡UI像在Tinder或Quizlet中一样,而不使用Foreach,一次布局所有的卡片(可能有很多)
我尝试不带任何修饰符地循环ForEach(array. indexs),并且所有卡片同时显示在堆栈中,但是我希望它们在用户刷当前卡片时更新。我不知道还有其他方法来编写更新视图的代码(初学者)。

struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
    
    VStack {
        ZStack {
            
            RoundedRectangle(cornerRadius: 20)
                .aspectRatio(CGSize(width: 150, height: 300), contentMode: .fit)
                .foregroundColor(.white)
                .shadow(radius: 5)
                .padding(50)
            
            ForEach(model.flashcard.reversed()) { card in
                AllCardView(flashcard: Flashcard(front: card.front, back: card.back))
            }
            .padding()
        }
    }
}

}

noj0wjuj

noj0wjuj1#

方法:

  • 使用ZStack堆叠卡片
  • 在卡上添加DragGesture
  • 使用手势上的.onChanged.onEnded移动卡片
  • 旋转卡片
  • 向卡片添加抵销
  • 使用withAnimation { }设置值更改的动画

下面给出的是一个粗略的实现,您可以将其用作指导并对其进行改进:

卡片:

import Foundation
import SwiftUI

struct Card: Identifiable {
    let id: Int
    let title: String
    let color: Color
}

型号:

class Model: ObservableObject {
    @Published var cards = [
        Card(id: 1, title: "1", color: .red),
        Card(id: 2, title: "2", color: .green),
        Card(id: 3, title: "3", color: .blue),
        Card(id: 4, title: "4", color: .yellow),
        Card(id: 5, title: "5", color: .purple),
        Card(id: 6, title: "6", color: .orange),
    ]
    
    func removeFirstCard() {
        guard !cards.isEmpty else {
            return
        }
        cards.remove(at: 0)
    }
}

卡片视图:

struct CardView: View {
    let title: String
    let color: Color
    
    @EnvironmentObject private var model: Model
    
    private let xthreshold = CGFloat(150)
    private let yMovement = CGFloat(10)
    
    @State private var xOffset = CGFloat(0)
    @State private var yOffset = CGFloat(0)
    
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 18)
                .foregroundColor(color)
            Text(title)
                .foregroundColor(.white)
        }
        .frame(width: 300, height: 400)
        .gesture(dragGesture)
        .offset(x: xOffset, y: yOffset)
        .rotationEffect(rotationAngle, anchor: rotationAnchor)
    }
    
    var rotationAngle: Angle {
        let degrees: Double
        switch xOffset {
        case 0:
            degrees = 0
        case ...0:
            degrees = -5
        case 0...:
            degrees = 5
        default:
            degrees = 0
        }
        return Angle(degrees: degrees)
    }
    
    var rotationAnchor: UnitPoint {
        xOffset >= 0 ? .topLeading : .topTrailing
    }
    
    var dragGesture: some Gesture {
        DragGesture(minimumDistance: 20)
            .onEnded { value in
                let xOffset: CGFloat
                let yOffset: CGFloat
                switch self.xOffset {
                case ...(-xthreshold):
                    print("negative")
                    xOffset = -200
                    yOffset = yMovement
                case -xthreshold...0:
                    print("negative - not enough")
                    xOffset = 0
                    yOffset = 0
                case xthreshold...:
                    print("positive")
                    xOffset = 200
                    yOffset = yMovement
                case 0...:
                    print("positive - not enough")
                    xOffset = 0
                    yOffset = 0
                default:
                    print("default")
                    xOffset = 0
                    yOffset = 0
                }
                
                withAnimation {
                    self.xOffset = xOffset
                    self.yOffset = yOffset
                    if xOffset != 0 {
                        model.removeFirstCard()
                    }
                }
            }
            .onChanged { value in
                switch value.translation.width {
                case ...0:
                    print("negative")
                    withAnimation {
                        yOffset = yMovement
                    }
                case 0...:
                    print("positive")
                    withAnimation {
                        yOffset = yMovement
                    }
                default:
                    print("default")
                    withAnimation {
                        yOffset = 0
                    }
                }

                xOffset += value.translation.width
            }
    }
}

内容视图:

struct ContentView: View {
    @StateObject var model = Model()
    var body: some View {
        ZStack {
            ForEach(model.cards.reversed()) { card in
                CardView(title: card.title, color: card.color)
                    .environmentObject(model)
            }
        }
    }
}

相关问题