SwiftUI 按钮操作不会更新我的观察对象
Posted
技术标签:
【中文标题】SwiftUI 按钮操作不会更新我的观察对象【英文标题】:SwiftUI Button action does not update my Observed Object 【发布时间】:2021-03-15 12:36:10 【问题描述】:我正在为棋盘游戏创建记分员。我创建了编号按钮,这些按钮应该通过按钮上的数字来增加我的分数。但是,当按钮被按下时,不会发生任何动作。当我设置一个断点时,我可以告诉按钮正在被调用,但没有发生任何动作——即使我输入了基本元素,例如更改我的玩家名称。你能帮我弄个按钮,按按钮上显示的数字增加“分数”吗?
struct ContentView: View
@EnvironmentObject var theGame:Game
@ObservedObject var player1: Player
@ObservedObject var player2: Player
@ObservedObject var player3: Player
@ObservedObject var player4: Player
@State var isPlayer1Active: Bool = false
@State var isPlayer2Active: Bool = false
@State var isPlayer3Active: Bool = false
@State var isPlayer4Active: Bool = false
var body: some View
VStack
AdBannerView()
HStack
VStack
Spacer()
HStack
VStack
Button(action:
player1.isPlayerActive = true
player2.isPlayerActive = false
player3.isPlayerActive = false
player4.isPlayerActive = false
theGame.activePlayer = player1.playerName
)
PlayerView(player: player1)
Button(action:
player1.isPlayerActive = false
player2.isPlayerActive = true
player3.isPlayerActive = false
player4.isPlayerActive = false
theGame.activePlayer = player2.playerName
)
PlayerView(player: player2)
VStack
Button(action:
player1.isPlayerActive = false
player2.isPlayerActive = false
player3.isPlayerActive = true
player4.isPlayerActive = false
theGame.activePlayer = player3.playerName
)
PlayerView(player: player3)
Button(action:
player1.isPlayerActive = false
player2.isPlayerActive = false
player3.isPlayerActive = false
player4.isPlayerActive = true
theGame.activePlayer = player4.playerName
)
PlayerView(player: player4)
addPointsCombinedView(player1: Player(), player2: Player(),player3: Player(), player4: Player())
.padding()
.layoutPriority(1)
.padding()
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView(player1: Player(), player2: Player(),player3: Player(), player4: Player())
.environmentObject(Game(numberOfPlayers: 4))
.previewDevice("iPad Pro (9.7-inch)")
播放器视图
struct PlayerView: View
@ObservedObject var player: Player
@EnvironmentObject var theGame:Game;
@State var changeName: Bool = false
var borderSize: CGFloat = 2
var body: some View
HStack
Text(player.playerName)
.foregroundColor(.white)
.padding()
VStack
Text("Score")
Text(player.formattedScore)
.foregroundColor(.white)
.padding()
.background(player.isPlayerActive ? Color.blue : Color.green)
.cornerRadius(25)
/* Extension that allows custom corner radius for each corner. This code was created by Mojtaba Hosseini and found on *** https://***.com/questions/56760335/round-specific-corners-swiftui*/
/* extension View
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View
clipShape(playerRoundedCornerView(radius: radius, corners: corners) )
*/
/*This code was created by Mojtaba Hosseini and found on *** https://***.com/questions/56760335/round-specific-corners-swiftui*/
struct playerRoundedCornerView: Shape
var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
struct PlayerView_Previews: PreviewProvider
static var previews: some View
PlayerView(player: Player())
加分按钮
struct addScoreButton: View
@ObservedObject var player1: Player
@ObservedObject var player2: Player
@ObservedObject var player3: Player
@ObservedObject var player4: Player
@EnvironmentObject var theGame:Game
var numberToAdd:String
var body: some View
Button(action:
player1.changePlayerName(newPlayerName: "Hello2")
switch theGame.activePlayer
case player1.playerName:
player1.addToScore(pointToAdd: addScore(numberToAdd: numberToAdd))
case player2.playerName:
player2.addToScore(pointToAdd: addScore(numberToAdd: numberToAdd))
default:
theGame.activePlayer = "hello world"
)
ZStack
Rectangle()
.fill(Color.gray)
//.frame(width: 75, height: 75, alignment: .center)
.frame(minWidth: 70, idealWidth: 75, maxWidth: 100, minHeight: 70, idealHeight: 75, maxHeight: 100, alignment: .center)
.padding(.bottom, 5)
Text("\(numberToAdd)")
.foregroundColor(.white)
.bold()
.font(.title)
struct addScoreButton_Previews: PreviewProvider
static var previews: some View
addScoreButton(player1: Player(), player2: Player(),player3: Player(), player4: Player(),numberToAdd: "+1")
func addScore(numberToAdd:String) -> Int
switch numberToAdd
case "+1":
return 1
case "+2":
return 2
case "+3":
return 3
case "+4":
return 4
case "+5":
return 5
case "+6":
return 6
case "+12":
return 12
case "-1":
return -1
case "-2":
return -2
default:
return -3
按钮的组合视图:
struct addPointsCombinedView: View
@ObservedObject var player1: Player
@ObservedObject var player2: Player
@ObservedObject var player3: Player
@ObservedObject var player4: Player
@EnvironmentObject var theGame:Game
var one:String = "+1"
var two:String = "+2"
var three:String = "+3"
var four:String = "+4"
var five:String = "+5"
var six:String = "+6"
var twelve:String = "+12"
var negOne:String = "-1"
var negTwo:String = "-2"
var body: some View
HStack
VStack
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4, numberToAdd: one)
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: four)
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: twelve)
.padding(.trailing, 3)
VStack
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: two)
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: five)
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: negOne)
VStack
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: three)
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: six)
addScoreButton(player1: player1, player2: player2,player3: player3, player4: player4,numberToAdd: negTwo)
.padding(.leading, 3)
struct addPointsCombinedView_Previews: PreviewProvider
static var previews: some View
addPointsCombinedView(player1: Player(), player2: Player(),player3: Player(), player4: Player())
玩家对象:
class Player:ObservableObject
@Published var playerName:String
@Published var score:[GameRound] = []
@Published var isPlayerPlayingThisGame:Bool
@Published var isPlayerActive:Bool
@Published var currentScore: Int
var formattedScore:String
String(currentScore)
//@Published let currentRound:Int
//@Published var beginningScore:Int
//@Published var endScore:Int
//@Published var pointsThisRound:[Int]
init()
playerName = "Player1"
let newGame = GameRound(newRound: 1,beginningScore: 0 )
isPlayerActive = false
isPlayerPlayingThisGame = false
currentScore = 0
score.append(newGame)
func changePlayerName(newPlayerName: String)
playerName = newPlayerName
/*adds the new points to the array of points made this round
and adds them to the current score */
func addToScore(pointToAdd: Int)
//score.last?.addScore(pointsToAdd: pointToAdd)
self.currentScore += pointToAdd
score.last?.endScore += pointToAdd
score.last?.pointsThisRound.append(pointToAdd)
/*starts a new round of the game*/
func newRound()
let newRound = GameRound(newRound:self.score.last!.currentRound+1,beginningScore: self.score.last!.endScore)
self.score.append(newRound)
GameRoundObject
class GameRound
let currentRound:Int
var beginningScore:Int
var endScore:Int
var pointsThisRound:[Int]
var scoreAsString:StringString(endScore)
init(newRound:Int, beginningScore: Int)
self.currentRound = newRound
self.beginningScore = beginningScore
self.endScore = newRound
self.pointsThisRound = [0]
func addScore(pointsToAdd:Int)
self.endScore += pointsToAdd
self.pointsThisRound.append(pointsToAdd)
func roundAsString()->String
var roundNumber:String
var round = "Round:"
roundNumber = "\(self.currentRound)"
round += roundNumber
return round
游戏对象
class Game:ObservableObject
@Published var player1 = Player()
@Published var player2 = Player()
@Published var player3 = Player()
@Published var player4 = Player()
@Published var activePlayer:String
@Published var game:[Player] = []
@Published var currerntRound: Int
init(numberOfPlayers: Int)
activePlayer = " "
currerntRound = 1
for i in 1...numberOfPlayers
switch i
case 1:
game.append(player1)
player1.isPlayerPlayingThisGame = true
case 2:
game.append(player2)
player2.isPlayerPlayingThisGame = true
case 3:
game.append(player3)
player3.isPlayerPlayingThisGame = true
case 4:
game.append(player4)
player4.isPlayerPlayingThisGame = true
default:
break
【问题讨论】:
【参考方案1】:您当前有一行正在创建新的 Player
实例,而不是引用已经创建的实例。
您的线路:
addPointsCombinedView(player1: Player(), player2: Player(),player3: Player(), player4: Player())
应该是:
addPointsCombinedView(player1: player1, player2: player2,player3: player3, player4: player4)
以上将解决您的问题。但是,总的来说,我还要说,在架构上,我不确定将所有玩家存储在Game
环境变量中是否有意义,该环境变量会发送到每个视图和传递每个玩家也可以作为@ObservableObject
参数。
【讨论】:
这很有效,谢谢。您对 Game 环境对象是正确的。坦率地说,这是我需要清理的旧代码,我只是在尝试新的东西。另一方面,有没有办法让我回答这个问题,以便我给你信用? 有。您可以单击绿色复选标记接受,然后单击向上箭头将其标记为有用。谢谢!以上是关于SwiftUI 按钮操作不会更新我的观察对象的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI - 从 Swift 类启动的可观察对象不会更新 ContentView() 上的 @ObservedObject