If I put a HStack in the content of the picker I get tripled rows per HStack. How is it possible to put the content in one row?
Picker: https://imgur.com/a/7GW1sHV
struct ContentView: View{
#State var number = 0
var body: some View{
Menu(content: {
Picker(selection: $number, content: {
Section{
ForEach(0..<5, content: {i in
HStack{
Image(systemName: "house")
Spacer()
Text("number: \(i)")
}
.tag(i)
})
}
Section{
HStack{
Image(systemName: "house")
Spacer()
Text("Section")
}
.tag(6)
}
}, label: {EmptyView()})
}, label: {
Text("number: \(number)")
.frame(width: 100, height: 30)
.background(Color.green)
})
}
}
Related
I created a program that helped me understand the basics of navigation links which I am still learning. I was wondering how I would get rid of the navigation links stacking on top of each other.
import SwiftUI
struct RedOneView: View {
var body: some View {
NavigationView{
VStack{
CircleViewNumber(color: .red, number: 1)
.navigationTitle("Red one")
.offset(y: -60)
NavigationLink(destination: BlueTwoView(color: .orange), label: {
Text("Blue View")
.bold()
.frame(width: 200, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
})
}
}
}
struct CircleViewNumber: View{
var color: Color
var number: Int
var body: some View{
ZStack{
Circle()
.frame(width: 200, height: 200)
.foregroundColor(color)
Text("\(number)")
.foregroundColor(.white)
.font(.system(size: 70, weight: .bold))
}
}
}
struct test: View{
var number: Int
var body: some View{
ZStack{
Circle()
.scale(1.5)
.foregroundColor(.blue)
Text("\(number)")
}
}
}
struct BlueTwoView: View {
var color: Color
var body: some View {
NavigationView{
VStack{
CircleViewNumber(color: color, number: 2)
.navigationTitle("Blue two")
.offset(y: -60)
NavigationLink(destination: GreenThreeView(), label: {
Text("Next Screen")
})
}
}
}
}
struct GreenThreeView: View {
var body: some View {
NavigationView{
VStack{
CircleViewNumber(color: .green, number: 2)
.navigationTitle("Green three")
.offset(y: -60)
NavigationLink(destination: test(number: 5), label: {
Text("Next Screen")
})
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
RedOneView()
}
}
}
So how would I go about getting rid of navigation link so that in you cannot just skip to the very first link (red one) but instead there is one button and you must go each screen individually.
You should use only one NavigationView in your navigation stack. So you have to get rid of nested NavigationView's in your components. You can simply delete NavigationView everywhere except RedOneView.
But I suggest creating RootView component with NavigationView and get rid of NavigationView in all child components
struct RootView: View {
var body: some View {
NavigationView {
RedOneView()
}
}
}
struct RedOneView: View {
var body: some View {
VStack {
CircleViewNumber(color: .red, number: 1)
.navigationTitle("Red one")
.offset(y: -60)
NavigationLink(destination: BlueTwoView(color: .orange), label: {
Text("Blue View")
.bold()
.frame(width: 200, height: 50)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
})
}
}
struct BlueTwoView: View {
var color: Color
var body: some View {
VStack {
CircleViewNumber(color: color, number: 2)
.navigationTitle("Blue two")
.offset(y: -60)
NavigationLink(destination: GreenThreeView(), label: {
Text("Next Screen")
})
}
}
}
//...
I have a list item with some text stuff, navigationLink and button to show .sheet.When I click on either navigation link or show sheet button both navigation destination and the sheet appear.How to avoid this behaviour?
Note: This is minimal produceable code.
struct ContentView: View {
#State var shouldSheetShow:Bool = false;
var body: some View {
NavigationView{
List{
VStack(alignment: .leading){
Text("Some Text Stuff")
NavigationLink(
destination: Text("navigation link"),
label: {
Text("Navigate To some view")
.background(Color.green)
})
Button(action: {
self.shouldSheetShow = true
}, label: {
HStack{
Text("Show sheet")
}
.background(Color.blue)
.sheet(isPresented: $shouldSheetShow, content: {
Text("sheet")
})
})
}
.frame(width: 300, height: 150, alignment: .center)
.background(Color.gray)
}
}
}
}
A possible solution is to replace the Button with Text plus an onTapGesture
Replace
Button(action: {
self.shouldSheetShow = true
}, label: {
HStack{
Text("Show sheet")
}
.background(Color.blue)
.sheet(isPresented: $shouldSheetShow, content: {
Text("sheet")
})
})
with
Text("Show sheet")
.background(Color.blue)
.sheet(isPresented: $shouldSheetShow, content: {
Text("sheet")
})
.onTapGesture {
self.shouldSheetShow = true
}
In my example code below, I have two tabs and within the main tab (Tab A) there are two "buttons" on the front page to allow the user to navigate to two views (View 1 or View 2) using navigationlinks. Within each of view 1 and view 2 there are further navigation links so my code (purposefully) resets the navigation stack for each view when you switch tabs and then return to the tab. Also, if you navigate to view 1 or view 2 (while still on the main tab (tab A)), tapping the main tab button (tab A) again brings you back to the front page (which presents the two buttons). This behaviour is what I need. The problem I now have is that the navigation links (to view 1 and view 2) don't work as intended. Sometimes clicking the view 1 button takes you to view 2 and sometimes it takes you to view 1. The same happens with the view 2 button. This must have something to do with how I reset the navigation stack for my other needs, but I'm not sure how to solve this. I include some minimal code to show this. Does anyone have an idea how to solve this? Thanks
struct ContentView: View {
#State var activeView: Int = 0
#State var showNavigation: Bool = false
let items = ["View1", "View2"]
var body: some View {
TabView(selection: Binding<Int> (
get: {
activeView
}, set: {
activeView = $0
showNavigation = false
}))
{
NavigationView {
HStack {
VStack {
NavigationLink(
destination: View1(), isActive: $showNavigation, label: {
Rectangle()
.fill(Color.red)
.cornerRadius(12)
.frame(width: 70, height: 70)
}).isDetailLink(false)
Text(items[0])
}
VStack{
NavigationLink(
destination: View2(), isActive: $showNavigation, label: {
Rectangle()
.fill(Color.red)
.cornerRadius(12)
.frame(width: 70, height: 70)
}).isDetailLink(false)
Text(items[1])
}
}.navigationTitle("")
.navigationBarHidden(true)
}
.tabItem {
Image(systemName: "a.circle")
Text("Main")
}
.tag(0)
View3()
.padding()
.tabItem {
Image(systemName: "b.circle")
Text("View 3")
}
.tag(1)
}
}
}
The problem seems to be that you're using the same showNavigation variable for both NavigationLinks.
I've changed the variable around a bit to hold an id and added a custom Binding to keep track of which NavigationLink should be active:
struct ContentView: View {
#State var activeView: Int = 0
#State var activeNavigationLink: Int = 0 //<-- Here
let items = ["View1", "View2"]
func navigationLinkBinding(id: Int) -> Binding<Bool> { //<-- Here
.init { () -> Bool in
activeNavigationLink == id
} set: { (newValue) in
if newValue {
activeNavigationLink = id
} else {
activeNavigationLink = 0
}
}
}
var body: some View {
TabView(selection: Binding<Int> (
get: {
activeView
}, set: {
activeView = $0
activeNavigationLink = 0 //<-- Here
}))
{
NavigationView {
HStack {
VStack {
NavigationLink(
destination: Text("View 1"), isActive: navigationLinkBinding(id: 1), label: { //<-- Here
Rectangle()
.fill(Color.red)
.cornerRadius(12)
.frame(width: 70, height: 70)
}).isDetailLink(false)
Text(items[0])
}
VStack{
NavigationLink(
destination: Text("View 2"), isActive: navigationLinkBinding(id: 2), label: { //<-- Here
Rectangle()
.fill(Color.red)
.cornerRadius(12)
.frame(width: 70, height: 70)
}).isDetailLink(false)
Text(items[1])
}
}.navigationTitle("")
.navigationBarHidden(true)
}
.tabItem {
Image(systemName: "a.circle")
Text("Main")
}
.tag(0)
Text("View 3")
.padding()
.tabItem {
Image(systemName: "b.circle")
Text("View 3")
}
.tag(1)
}
}
}
I've added a .toolbar to the top level of a NavigationView that will eventually be used to select items in a list without using swipe gestures (up button, down button, etc.). I also have a .navigationBar going on, to access other views for Account and Settings.
For the most part it's looking really good, but when I follow a NavigationLink (in .navigationBarItems) within NavigationView, and then use the built-in back navigation, my .toolbar disappears from the top level.
Am I putting the .toolbar in the wrong place? It feels like a problem with .navigationViewStyle(StackNavigationViewStyle()) because when I comment that out, the toolbar will not disappear upon navigation... but I don't like how the default behavior works in landscape so I'm relying on it.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
Group {
Section(header: Text("List Items").foregroundColor(.gray).font(.footnote)) {
Text("List Item One")
Text("List Item Two")
Text("List Item Three")
}
}
}.navigationTitle("Top Level List").navigationBarTitleDisplayMode(.inline)
.ignoresSafeArea(.all)
// MARK: NAVBAR
.navigationBarItems(
leading:
NavigationLink(destination: UserView()) {
Image(systemName: "person.crop.circle").font(.title2)
},
trailing:
NavigationLink(destination: SettingsView()) {
Image(systemName: "gear").font(.title2)
})
//MARK: - CONTENT NAV
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: {}, label: {Label("Mute", systemImage: "speaker.slash.fill")})
Spacer()
Button(action: {}, label: {Label("Repeat", systemImage: "arrow.clockwise")})
Spacer()
Button(action: {}, label: {Label("Previous", systemImage: "arrow.up")})
Spacer()
Button(action: {}, label: {Label("Next", systemImage: "arrow.down")})
Spacer()
Button(action: {}, label: {Label("Select", systemImage: "arrow.right")})
}
}
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct UserView: View {
#State private var username: String = ""
#State private var password: String = ""
var body: some View {
Form {
TextField("Username", text: $username)
SecureField("Password", text: $password)
}
.navigationBarTitle("Account").font(.subheadline)
}
}
struct SettingsView: View {
#State private var setting1: String = ""
#State private var setting2: String = ""
var body: some View {
Form {
TextField("Setting One", text: $setting1)
SecureField("Setting Two", text: $setting2)
}
.navigationBarTitle("Settings").font(.subheadline)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You right, it's in a wrong place. Here is how it should be if you need a toolbar always shown:
struct ContentView: View {
var body: some View {
NavigationView {
List {
Group {
Section(header: Text("List Items").foregroundColor(.gray).font(.footnote)) {
Text("List Item One")
Text("List Item Two")
Text("List Item Three")
}
}
}.navigationTitle("Top Level List").navigationBarTitleDisplayMode(.inline)
.ignoresSafeArea(.all)
// MARK: NAVBAR
.navigationBarItems(
leading:
NavigationLink(destination: UserView()) {
Image(systemName: "person.crop.circle").font(.title2)
},
trailing:
NavigationLink(destination: SettingsView()) {
Image(systemName: "gear").font(.title2)
})
//MARK: - CONTENT NAV
}.navigationViewStyle(StackNavigationViewStyle())
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button(action: {}, label: {Label("Mute", systemImage: "speaker.slash.fill")})
Spacer()
Button(action: {}, label: {Label("Repeat", systemImage: "arrow.clockwise")})
Spacer()
Button(action: {}, label: {Label("Previous", systemImage: "arrow.up")})
Spacer()
Button(action: {}, label: {Label("Next", systemImage: "arrow.down")})
Spacer()
Button(action: {}, label: {Label("Select", systemImage: "arrow.right")})
}
}
}
}
How do you resize the picker view in SwiftUI? I need to change the width that it takes up. My code below is just a simple view with a picker inside it. Changing the width parameter does not change the width of the picker view.
struct CalibrationBar: View {
#State var tone = Int()
var body: some View{
HStack{
Button(action: {
playTone(tone: self.tone, amp: 50, stop: true)
}) {
Text("50 dB")
}
.frame(width: 60.0)
Picker(selection: .constant(1), label: Text("")) {
Text("+0").tag(1)
Text("+2").tag(2)
Text("+4").tag(3)
}
.clipped()
.frame(minWidth: 0, maxWidth: 100)
.labelsHidden()
}
}
}
struct ContentView: View {
var body: some View{
HStack{
Button(action: {
}) {
Text("50 dB")
}
.frame(width: 60.0)
VStack {
Picker(selection: .constant(1), label: Text("")) {
Text("+0").tag(1)
Text("+2").tag(2)
Text("+4").tag(3)
}
//.clipped()
.frame(width: 50)
.clipped()
}.border(Color.red)
}
}
}