I am building a fitness app where user selects one of the programs from the list and when he clicks on selected program a new view appears with video playing (video has it's countdown timer on it).
I built the screen using NavigationView/NavigationLink each having it's "destination view" with it's own params.
let sets: [TrainingSet]
init() {
self.sets = [set1,set2,set3]
}
var body: some View {
NavigationView {
VStack {
ForEach(self.sets) { set in
NavigationLink(destination: ExerciseVideoView(items: set.items).navigationBarBackButtonHidden(true)) {
VStack {
Image("group-\(set.image)")
.resizable()
.renderingMode(.original)
.frame(height: 200, alignment: .leading)
.overlay(
Text(set.purpose)
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(.white)
)
Color.blue
.frame(maxWidth: .infinity)
.overlay(
Text(set.purpose)
.foregroundColor(.white)
)
}
}
}
}
}
}
1) I noticed that when the parent view is built, all destination views (ExerciseVideoView) get executed even before user clicks on corresponding button. My countdown timers start in background. I was supposed to see them launched when user click on NavigationLink and new view is "executed". Is that correct behaviour? Can I make destination view "executed/started" when they are shown?
2) The second problem is I wanna show the images with blue buttons below each of them (I put them both inside a VStack container). But when I launch my app only the images are shown but "Color.blue" rectangles are not visible. Why is that? How to make them visible as well?
Related
I'm dipping my toe into SwiftUI and WatchOS for the first time. I'm making good progress, but I can't figure out how to get rid of the black "gutters" on either side of my Image controls. I've tried setting all the backgrounds to white, but the gutter persists.
What property on which view do I need to set to change the color of the gutters to match the background?
SwiftUI
struct ContentView: View {
var body: some View {
List {
Image("cat-1").resizable().scaledToFill().background(Color.white)
Image("cat-2").resizable().scaledToFit().padding(5).background(Color.white)
Image("cat-3").resizable().scaledToFit().padding(.top, 5).background(Color.white)
}.background(Color.white).listStyle(CarouselListStyle())
.background(Color.white)
}
}
Try adding a
.listRowPlatterColor(.clear)
put it inside the list like this...
struct ContentView: View {
var body: some View {
List {
Image("cat-1")
.resizable()
.scaledToFit()
.listRowPlatterColor(.clear)
Image("cat-2").resizable().scaledToFit().padding(5).background(Color.white)
Image("cat-1")
.resizable()
.scaledToFit()
.padding(.top, 5)
.background(Color.white)
}
.listStyle(CarouselListStyle())
}
}
I put it in the first item and left it off of the second and third so that you could see the difference. This other question can provide some more details:
How to style rows in SwiftUI List on WatchOS? .
You should then be able to style it however you like.
I'm a newbie, using XCode 13.0 to create a very basic app that needs to have a Settings view. I'd like to navigate to the Settings view on tapping a label. To do that, it seemed sensible to use a NavigationView with a NavigationLink.
Unfortunately, I'm encountering a formatting issue that creates a mess of the HStack in which the Setting label (gear icon) resides, as show below:
This is what I want, a result of the following code:
HStack(spacing: 25) {
... other labels
Label ("", systemImage: "gear")
.foregroundColor(.gray)
.font(.title)
.onTapGesture(perform: {
// Set a state variable that triggers an extension
// that brings up the SettingsView
})
}
This is what happens when NavigationView encapsulates the gear icon label. Note the vertical and horizontal white space around it.
HStack(spacing: 25) {
... other labels
NavigationView {
NavigationLink(destination: SettingsView()) {
Label ("", systemImage: "gear")
.foregroundColor(.gray)
.font(.title)
}.navigationBarTitle(Text(""))
}
}
I've, literally, spent weeks (sporadically) on this issue, looking up dozens of answers and trying various formatting options, without luck. I've also tried encapsulating parent and grandparent stacks into the NavigationView. To no avail. Surely, this is something trivial. Can somebody point me in the right direction?
p.s. there are other issues in that that Navigation link opens as a sub-window; I plan to tackle that later.
Edit: Right, so I tried using Yrb's code:
HStack(spacing: 25) {
... other labels
NavigationView {
NavigationLink(destination: Text("Linked View")) {
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.title)
}
.fixedSize()
.background(Color.red)
}
]
Unfortunately, there's no substantive change...
In diagnosing these sort of issues, it helps to throw a .background() with a color on. You can then see the issue. In this case, it was twofold, one, you need to use a .fixedSize to shrink the view to its smallest dimensions necessary. That would leave you with the icon plus a little space. That was due to you using a label as it was leaving a spot for the Text("") that you used as a fill in. Since you only want the image, use Image(systemName:) The code then comes out like this:
struct NavLinkNoSpace: View {
var body: some View {
NavigationView {
NavigationLink(destination: Text("Linked View")) {
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.title)
}
.fixedSize()
// Setting this shows you what space you are using. Remove it when you are done
.background(Color.red)
}
}
}
A couple more things. If you have not ever set the NavigationTitle, you don't need to set it to "". In your example, there was no title, so I simply removed it and there was no effect.
More importantly, and it was addressed by some of the comments, you should only have one NavigationView in the view hierarchy. As long as you are in the hierarchy, you do not need to wrap things like NavigationLink to have them work. You can always throw one around your view call in the preview provider if you are in a child view, to show what things look like, and to test NavigationLinks, etc., but do not just put them in to your main code. It will lead to undesirable outcomes.
To summarize what worked to fix the primary problem, that of formatting: The key was in figuring what to encapsulate within the NavigationView. My mistake was to assume that only the NavigationLink needed to be in the NavigationView.
What worked was to place all the contents of the body into the NavigationView, like below:
var body: some View {
NavigationView {
VStack(spacing: -10) {
Text(appName)
.font(.largeTitle)
.foregroundColor(.blue)
.padding(.bottom)
// ...
// includes a bunch of VStacks and HStacks
// ... and finally
NavigationLink(destination: SettingsView()) {
Image(systemName: "gear")
.foregroundColor(.gray)
.font(.title)
// ... more stuff
// ... and finally
}.padding(.top, -100) // NavigationView
} // body
I have a horizontal ScrollView on top of a MapView.
The ScorllView is a collection of Buttons. It is weird that the buttons in the ScrollView are sometime tapable and sometimes not. First tap always works but after that I have to scroll a bit, tap around different areas in the button, make some secret prayers and then it works!
I tried disabling/removing all other components in the view, but still unable to figure out the root cause.
Has anyone experience this ?
I stuck with a same issue with horizontal ScrollView on top and List. While debugging I added empty .onTapGesture to ScrollView and it somehow fix my issue.
VStack(spacing: 0) {
ScrollView(.horizontal) {
HStack {
Button("one") {}
Button("two") {}
Button("three") {}
}
}
.onTapGesture { // <---- fix
}
List {
}
}
I also faced the same issue for Horizontal Scroll view in Swiftui dark theme "CameraTimerItem" buttons not clickable (Problem with dark theme only). Then I put a onTapGesture without any action. It's starts to work normally. I think it's a error of SwiftUI.
VStack (alignment:.center){
ScrollView(.horizontal, showsIndicators: false) {
HStack{
ForEach(timeSlots,id: \.self) { item in
CameraTimerItem(cellTitle: item)
}
}
.frame(width: AppUtils.width, alignment: .center)
}
.onTapGesture {
// <---- This is the solution
}
}
To anyone else having this issue, instead of adding an empty .onTapGesture view modifier, check that any HStacks in the ScrollView hierarchy have a .contentShape(Rectangle()) modifier. By default, HStacks don't accept taps in between their child views, and depending on your child view's layout this can cause taps to be missed even when it looks like they should be landing. .contentShape(Rectangle()) makes the entire frame of the HStack tappable.
NavigationLink("", destination: login(),isActive: $goWhenTrue)
Button (action: { print("Button Tapped")}, label: {
Text("LogOut")
.font(.headline)
.foregroundColor(.white)
.frame(width: 340, height: 50)
.background(Color.blue)
.clipShape(Capsule())
.padding()
.onTapGesture {
self.goWhenTrue = true
if ((UserDefaults.standard.string(forKey: "Username") != "nil")) {
UserDefaults.standard.removeObject(forKey: "Username")
}
}
})
In this program, I am logging out from my app, I used a NavigationLink on the logout button and I cleared the data with UserDefaults as you can see above.
here when I click the back button, I'm again going back to the home page rather than hanging in my login page.
I want to delete the values from UserDefaults whenever I log out from the session.
Can anybody give me a solution to this problem?
I have tried to have a layout like the following screen shots. Basically a long vertical scrolling view, with a number of round corner panes.
My code as follows:
struct DetailView: View {
#EnvironmentObject var modelData: ModelData
var body: some View {
ZStack {
Image("Dummy")
.resizable()
.aspectRatio(contentMode: .fill)
.opacity(0.2)
.frame(width: .infinity, height: .infinity)
.edgesIgnoringSafeArea(.all)
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 0) {
TabView {
VStack(alignment: .leading, spacing:0) {
HStack {
Text("A long Text title").font(.title)
Spacer()
}.frame(width:UIScreen.main.bounds.size.width*0.9)
HStack {
Text("A long Text title").font(.title)
Spacer()
}.frame(width:UIScreen.main.bounds.size.width*0.9)
HStack {
Text("A long Text title").font(.title)
Spacer()
}.frame(width:UIScreen.main.bounds.size.width*0.9)
HStack {
Text("A long Text title").font(.title)
Spacer()
}.frame(width:UIScreen.main.bounds.size.width*0.9)
}
}.tabViewStyle(PageTabViewStyle())
.background(Color.green)
TabView {
ImageView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(UIConstants.cardCornerRadius)
ImageView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(UIConstants.cardCornerRadius)
ImageView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(UIConstants.cardCornerRadius)
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.background(Color.red)
TabView {
TextInfoView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(UIConstants.cardCornerRadius)
.padding([.horizontal])
}.tabViewStyle(PageTabViewStyle())
.background(Color.green)
TabView {
TextInfoView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(UIConstants.cardCornerRadius)
.padding([.horizontal])
}.tabViewStyle(PageTabViewStyle())
.background(Color.purple)
}
}
}
}
}
struct TextInfoView: View {
var body: some View {
VStack {
Text("Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview. Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.").padding()
}
.background(Color.yellow)
}
}
struct ImageView: View {
var body: some View {
Image("Dummy")
.resizable()
.aspectRatio(contentMode: /*#START_MENU_TOKEN#*/.fill/*#END_MENU_TOKEN#*/)
.frame(height:UIScreen.main.bounds.size.height*0.7)
}
}
The results as follows:
A few issues here:
You can see that I tried to wrap the TextInfoView with a TabView as well. It is because if I do not enclose it in a TabView, it cannot align with the TabView with ImageView above. Any method to solve this issue?
At the top, the green area. Why there is such large padding around the text? How can I remove those extra green area? I want it to be tight at top and bottom.
If I do not add .frame() for the green area text, I found that the text gone, and cannot align to the left. Any method to solve this?
struct DetailViews: View {
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.all)
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) {
VStack{
Text("A long Text Title")
Text("A long Text Title")
Text("A long Text Title")
Text("A long Text Title")
}
.frame(maxWidth: .infinity)
.background(Color.yellow)
TabView {
ImageView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(15)
ImageView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(15)
ImageView()
.frame(width:UIScreen.main.bounds.size.width*0.9)
.cornerRadius(15)
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
.background(Color.red)
TextInfoView()
.cornerRadius(15)
.padding()
.background(Color.blue)
TextInfoView()
.cornerRadius(15)
.padding()
.background(Color.purple)
}
}
}
}
}
struct TextInfoView: View {
var body: some View {
VStack {
Text("Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview. Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.Learn how to use SwiftUI to compose rich views out of simple ones, set up data flow, and build the navigation while watching it unfold in Xcode’s preview.")
.fixedSize(horizontal: false, vertical: true).padding()//added
}
.background(Color.yellow)
}
}