Hi, I'm facing a problem where if I click a NavigationLink and then go back to that page, the item I just clicked stays selected. It's been pretty frustrating. Here is my code! Thanks :)
struct EventsListView: View {
@EnvironmentObject var viewModel: OlympicGame
@State var showEditEvent: Bool = false
@State var showAddCustomPoints: Bool = false
var body: some View {
VStack {
GeometryReader { geometry in
VStack {
List {
Section(header: VStack(alignment: .leading) {
Text("Open:").font(.headline)
}
) {
ForEach(self.viewModel.eventsList) { event in
if event.completed == false {
NavigationLink(destination: EventInProgressView(event: event) .environmentObject(viewModel)) {
EventsListItemView(event: event)
.foregroundColor(Color.black)
.environmentObject(viewModel)
}.listStyle(DefaultListStyle())
}
}.onDelete(perform: delete)
}.textCase(nil)
if self.viewModel.eventsList.filter { $0.completed == true }.count > 0 {
Section(header: VStack(alignment: .leading) {
Text("Completed:").font(.headline)
}) {
ForEach(self.viewModel.eventsList.filter { $0.completed == true }) { event in
NavigationLink(destination: EventInProgressView(event: event).environmentObject(viewModel)) {
EventsListItemView(event: event)
.foregroundColor(Color.black)
.environmentObject(viewModel)
}.listStyle(PlainListStyle())
}
}
}
if self.viewModel.eventsList.isEmpty {
VStack {
Spacer()
Image("SalmonLeaps")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300, height: 300)
.padding(.vertical, 40)
}
}
}
VStack {
if self.viewModel.eventsList.filter { $0.completed == false }.isEmpty && self.viewModel.eventsList.filter { $0.completed == true }.count > 0 {
finishView()
}
pointsView(for: geometry.size)
}
}
}
}
.navigationBarTitle("Events")
.navigationBarItems(
trailing:
Button(action: { self.showEditEvent.toggle() }) {
EventsListNewItemView()
}
.padding()
.sheet(isPresented: $showEditEvent) {
NewEventView(isShowing: $showEditEvent)
.environmentObject(viewModel)
}
)
}
func finishView() -> some View {
NavigationLink(destination: EndScreenView().environmentObject(viewModel)) {
Text("🏅 Tap here to finish! Or create more events!").foregroundColor(.accentColor)
}
}
func pointsView(for size: CGSize) -> some View {
VStack(alignment: .leading) {
Text("Point Totals").font(.headline).padding(.horizontal, 30)
HStack {
HStack {
Circle()
.fill(viewModel.team1.color)
.frame(width: teamScoreCircleRadius(for: size), height: teamScoreCircleRadius(for: size))
.shadow(radius: 1)
Text(String(viewModel.team1.points))
.font(.system(size: teamScoreFontSize(for: size)))
}.padding()
HStack {
Circle()
.fill(viewModel.team2.color)
.frame(width: teamScoreCircleRadius(for: size), height: teamScoreCircleRadius(for: size))
.shadow(radius: 1)
Text(String(viewModel.team2.points))
.font(.system(size: teamScoreFontSize(for: size)))
}.padding()
Spacer()
Button(action: { self.showAddCustomPoints.toggle() }) {
Image(systemName: "plus").imageScale(.large).padding(.horizontal)
}
.foregroundColor(.accentColor)
.padding()
.sheet(isPresented: $showAddCustomPoints) {
AddCustomPoints(isShowing: $showAddCustomPoints)
.environmentObject(viewModel)
}.buttonStyle(PlainButtonStyle())
}.padding(.horizontal)
}
}
func teamScoreCircleRadius(for size: CGSize) -> CGFloat {
let x = min(size.height, size.width)
return x/15
}
func teamScoreFontSize(for size: CGSize) -> CGFloat {
let x = min(size.height, size.width)
return x/20
}
func delete(at offsets: IndexSet) {
print(offsets)
viewModel.removeEvent(at: offsets)
}
}
Post
Replies
Boosts
Views
Activity
Hi there! I'm trying to separate my NavigationLinks because when I click a navigationLink, the entire VStack gets clicked but I only wan't one NavigationLink. Could someone help me fix this?
var body: some View {
VStack {
GeometryReader { geometry in
VStack {
List {
VStack(alignment: .leading) {
Text("Open:").font(.headline).padding()
Divider()
ForEach(self.viewModel.eventsList) { event in
if event.completed == false {
NavigationLink(destination: EventInProgressView(event: event) .environmentObject(viewModel)) {
EventsListItemView(event: event)
.foregroundColor(Color.black)
.environmentObject(viewModel)
}
}
}.onDelete(perform: delete)
}
//there's some more stuff down here
Hi! So the problem that I'm facing is that I'm splitting up a single array into 2 different ones using the .filter method. The problem is that when I try to delete from the "Open lists," it is confused because it deletes from the original, non-split-up eventsList. For example, if I make 3 list items and then mark the 2nd one as complete so it goes into the other list and then try to delete the 2nd one in open (which is actually the 3rd one), it deletes the 2nd one (which is in the completed section). I hope I explained that correctly...
Here is my code for reference..
struct EventsListView: View {
@EnvironmentObject var viewModel: OlympicGame
@State var showEditEvent: Bool = false
var body: some View {
VStack {
GeometryReader { geometry in
List {
HStack {
//other stuff
}
Text("Open:").font(.headline)//shadow(radius: 10)
ForEach(self.viewModel.eventsList.filter { $0.completed == false }) { event in
NavigationLink(destination: EventInProgressView(event: event)) {
EventsListItemView(event: event)
.foregroundColor(Color.black)
.environmentObject(viewModel)
}
}.onDelete(perform: delete)
if self.viewModel.eventsList.filter { $0.completed == true }.count > 0 {
Text("Completed:").font(.headline)
ForEach(self.viewModel.eventsList.filter { $0.completed == true }) { event in
NavigationLink(destination: EventInProgressView(event: event)) {
EventsListItemView(event: event)
.foregroundColor(Color.black)
.environmentObject(viewModel)
}
}
}
}
}
}
//other stuff was here
//MARK: Intents
func delete(at offsets: IndexSet) {
print(offsets)
viewModel.removeEvent(at: offsets)
}
}
Here is what my delete looked like in my model:
mutating func removeEvent(at offsets: IndexSet) {
eventsList.remove(atOffsets: offsets)
}
My question is, how do I make it so that when I delete from one ForEach, it actually deletes the one that I tried to delete? Thanks everyone!
Hello everyone. I am wanting to be able to adjust the size of buttons in a VStack based on how big the screen is but when I try to use GeometryReader, my buttons end up being on the left side of the screen. I am putting the GeometryReader outside of the VStack by the way.
Another question: how can I navigate back to the previous screen as a result of pressing a button on one of my actionSheets?
struct EventInProgressView: View {
@EnvironmentObject var viewModel: OlympicGame
var event: OlympicModel.Event
@ObservedObject var stopWatchManager = StopWatchManager()
@State private var showingActionSheet = false
var body: some View {
VStack {
if let description = event.description {
Text(description)
.font(.headline)
.opacity(0.70)
.padding()
}
if event.stopwatchRequested {
timer
Divider()
ScrollView {
ForEach(event.times.indices, id: \.self) { index in
HStack {
Text(String(index + 1) + ".")
.padding(.horizontal)
Spacer()
Text(String(format: "%.2f", event.times[index]))
.padding(.horizontal)
}
.padding(.horizontal)
}
}.padding(.vertical)
Divider()
}
Button(action: {
self.showingActionSheet = true
}) {
Text("Finish").font(.title3).padding()
}
.actionSheet(isPresented: $showingActionSheet) {
ActionSheet(title: Text("Declare Winner for \(event.name)"), message: Text("Who was victorious this round?"), buttons: [
.default(Text(viewModel.team1.name)) {
viewModel.finishEvent(team: viewModel.team1, event: event)
},
.default(Text(viewModel.team2.name)) {
viewModel.finishEvent(team: viewModel.team2, event: event)
},
.cancel()
])
}
}
.navigationTitle(event.name)
}
Here is the code for the timer variable on line 19:
var timer: some View {
VStack {
Text(String(format: "%.2f", stopWatchManager.secondsElapsed))
.font(.custom("Avenir", size: 55))
.padding(.vertical, 80)
if stopWatchManager.mode == .stopped {
Button(action: {self.stopWatchManager.start()}) {
TimerButton(label: "Start", buttonColor: .blue)
}
Button(action: {
stopAndSave()
}) {
TimerButton(label: "Save and Reset", buttonColor: .red)
}.padding()
.disabled(true)
.opacity(0.0)
}
if stopWatchManager.mode == .running {
Button(action: {self.stopWatchManager.pause()}) {
TimerButton(label: "Pause", buttonColor: .orange)
}
Button(action: {
stopAndSave()
}) {
TimerButton(label: "Save and Reset", buttonColor: .red)
}.padding()
.disabled(true)
.opacity(0.0)
}
if stopWatchManager.mode == .paused {
Button(action: {self.stopWatchManager.start()}) {
TimerButton(label: "Resume", buttonColor: .blue)
}
Button(action: {
stopAndSave()
}) {
TimerButton(label: "Save and Reset", buttonColor: .red)
}
.padding()
}
}
Where should I be putting the GeometryReader so that it doesn't align to the left? How have people been solving this in the past?
Hi everyone. I'm having trouble with a weird space that appears when I attempt to apply a NavigationLink to a view that has its own NavigationBarItems written inside of the struct. This is what my code looks like (but only pay attention to the NavigationView, NavigationBarTitle, NavigationBarItems stuff):
struct ContentView: View {
@ObservedObject var viewModel: OlympicGame = OlympicGame()
var body: some View {
TeamCreateView()
.environmentObject(viewModel)
}
}
struct TeamCreateView: View {
@EnvironmentObject var viewModel: OlympicGame
@State var showTeamEditView: Bool = false
var body: some View {
NavigationView {
GeometryReader { geometry in
VStack {
Button(action: {
self.showTeamEditView.toggle()
}) {
VStack(alignment: .leading) {
team1View().padding()
}.frame(height: geometry.size.height * 0.45)
}
.sheet(isPresented: $showTeamEditView) {
TeamEditView(team: viewModel.team1, isShowing: $showTeamEditView).environmentObject(viewModel)
}
Divider()
Button(action: {
self.showTeamEditView.toggle()
}) {
VStack(alignment: .leading) {
team2View().padding()
}.frame(height: geometry.size.height * 0.5)
}
.sheet(isPresented: $showTeamEditView) {
TeamEditView(team: viewModel.team2, isShowing: $showTeamEditView).environmentObject(viewModel)
}
}
.foregroundColor(Color.black)
.navigationBarTitle("Team Select")
.navigationBarItems(
leading:
Button("Back") {
},
trailing:
NavigationLink(destination: EventsListView()) {
Text("Next")
}
)
}
}
}
struct EventsListView: View {
@EnvironmentObject var viewModel: OlympicGame
@State var showEditEvent: Bool = false
var body: some View {
NavigationView {
List {
ForEach(self.viewModel.eventsList) { event in
Button(action: {
print("Size of eventsList")
}) {
EventsListItemView(event: event)
.foregroundColor(Color.black)
}
}
.onDelete(perform: delete)
}
.listStyle(PlainListStyle())
}
.navigationBarTitle("Events")
.navigationBarItems(
trailing:
Button(action: { self.showEditEvent.toggle() }) {
EventsListNewItemView()
}
.padding()
.sheet(isPresented: $showEditEvent) {
NewEventView(isShowing: $showEditEvent)
.environmentObject(viewModel)
}
)
}
func delete(at offsets: IndexSet) {
viewModel.removeEvent(at: offsets)
}
}
There is a weird space that appears between my NavigationBarTitle and the List on my EventsListView. Am I doing Navigation wrong? Could someone maybe show me how to do NavigationBarItems correctly?
Here is a picture of what the space looks like:
https://ibb. co/G745tWc (delete the space)
Hi everyone, I'm trying to initialize a view that uses a another struct. I want to pull that struct apart so that I can use those parts to fill in some TextFields with some already existing data, if it exists. Here is what my code looks like:
struct TeamEditView: View {
var team: OlympicModel.Team
@Binding var isShowing: Bool
@State var name: String = team.name
@State var playersArray: [String] = team.players
@State var playerNameToAdd: String = ""
@State var color: Color = team.color
@State var mascot: String = team.mascot
I get the error: "Cannot use instance member 'team' within property initializer; property initializers run before 'self' is available"
TextField("Team Name", text: $name)
I want to eventually put these vars into TextFields like this, so users can edit it.
I'm not sure what I should do here. Could I get some help?