问题
Every time I Tap the button I would like a new cardView to appear. I am wondering if this is possible in swiftUI and if so what action I would need to do it. It would be even better if I am able to pass some parameters in to the cardView struct but any help would be great!
struct ContentView: View {
var body: some View {
ZStack {
VStack {
TextButton(action: {print("Button tapped")}, text: "new card")
CardView()
}
}
}
}
struct CardView: View {
var body: some View {
ZStack {
Rectangle()
.fill(Color(#colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1)))
.frame(width: 100, height: 100 * 1.618)
.cornerRadius(16)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.1), radius: 1, x: 0, y: 1)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.2), radius: 10, x: 0, y: 10)
VStack {
Text("Card")
.font(.system(size: 10) )
.foregroundColor(.white)
.bold()
}
}
}
}
struct TextButton: View {
let action: () -> Void
let text: String
var body: some View {
Button(action: action, label: {
Text(text)
.padding(.horizontal, 16)
.padding(.vertical, 16)
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(.infinity)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.1), radius: 1, x: 0, y: 1)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.2), radius: 10, x: 0, y: 10)
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
} ```
回答1:
In SwiftUI, the View reflects the State data, so you don't modify the View directly, but rather modify the State data, and build the View based on the State. This is a core principle behind SwiftUI, and it allows you to separate the View concerns from the data that drives it (ViewModel in some lingo).
So, let's assume that we have a data model for a Card
(make it conform to Identifiable
- this will be needed later):
struct Card: Identifiable {
let id = UUID()
let name: String
}
And let's define an array of cards as a state variable in your View:
@State private var cards: [Card] = [Card(name: "foo")]
Then the body could display these cards with a ForEach
or in a List
view:
var body = some View {
VStack() {
Button("Add Card") {
self.cards.append(Card(name: "I'm an added card"))
}
ForEach(cards) { card in
CardView(for: card) // if your CardView had parameters
}
}
}
What happens is that the closure for the button adds a new Card
instance to the cards
state variable. That's it. It doesn't change anything in the View directly. The View sees the change (that's what SwiftUI does behind the scenes) and re-renders itself.
The reason you needed a Card
to conform to Identifiable
was to let the ForEach
know how to uniquely identify each card. Without conforming to identifiable, you could use a key path like so:
ForEach(cards, id: \.self) { card in
// ...
}
回答2:
check this out:
import SwiftUI
struct ContentView: View {
@State var cards: [CardView] = [CardView()]
var body: some View {
VStack {
TextButton(action: {
print("Button tapped")
self.cards.append(CardView())
}, text: "new card")
ZStack {
ForEach(cards, id: \.self) { card in
card
.rotationEffect(card.angle)
}
}
}
}
}
struct CardView: View, Hashable, Identifiable {
var id = UUID()
var angle : Angle {
let angle = Angle(degrees: Double.random(in: 0...30))
print(angle.degrees)
return angle
}
var body: some View {
ZStack {
Rectangle()
.fill(Color(#colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1)))
.frame(width: 100, height: 100 * 1.618)
.cornerRadius(16)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.1), radius: 1, x: 0, y: 1)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.2), radius: 10, x: 0, y: 10)
VStack {
Text("Card \(angle.degrees)")
.font(.system(size: 10) )
.foregroundColor(.white)
.bold()
}
}
}
}
struct TextButton: View {
let action: () -> Void
let text: String
var body: some View {
Button(action: action, label: {
Text(text)
.padding(.horizontal, 16)
.padding(.vertical, 16)
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(.infinity)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.1), radius: 1, x: 0, y: 1)
.shadow(color: Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)).opacity(0.2), radius: 10, x: 0, y: 10)
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
来源:https://stackoverflow.com/questions/61895745/in-swiftui-is-it-possible-to-add-a-new-view-onto-the-screen-with-a-button