Multiple Picker views: Inconsistent, cycle drop down lists - swiftui

I have a form with three different picker views. When I run the app and click on one of the pickers, the drop-down content is populated from another picker and it spontaneously cycles through the other two picker contents before returning to the main view. I am gogin to kick myself when someone points to something very fundamental and basic.... but here is the code . And thanks in advance!
var body: some View {
Form{
VStack {
HStack {
Text("PaO2")
TextField("mmHg", text: $PaO2)
.keyboardType(.numberPad)
Spacer()
Text("O2(%)")
TextField("%", text: $FiO2)
.keyboardType(.numberPad)
}
Toggle("Mechnical Ventilation", isOn: $MV)
HStack {
Text("Platelets")
TextField("(x1000)", text: $Platelets)
.keyboardType(.numberPad)
}
Picker(selection: $GCSSelected, label: Text("Glasgow Coma Scale")) {
ForEach(0..<GCS.count){ index1 in
Text(self.GCS[index1]).tag(index1)
}
}
Spacer()
Picker(selection: $HDSelected, label: Text("MAP/use of vasoactive Rx")){
ForEach(0..<HD.count){ index2 in
Text(self.HD[index2]).tag(index2)
}
}
HStack{
Text("Bilirubin")
TextField("mg/dL", text: $Bili)
.keyboardType(.numbersAndPunctuation)
}
Picker(selection: $RenalSelected, label: Text("Creatinine or Urine output")){
ForEach(0..<Renal.count){ index3 in
Text(self.Renal[index3]).tag(index3)
}
}
}
}
}
}

The issue is due to used single view for entire Form content, but you should not, so
var body: some View {
Form{
VStack { // << remove this container and let every picker be in own row

Related

Centering Item Inside Horizontal Stack with left and right views doesn't work with DatePicker

There was a similar question Center Item Inside Horizontal Stack that I followed the Asperi's basic answer that suited for me ( other answer did not worked, too).
struct HeaderTestView: View {
#State private var currentDate = Date()
var body: some View {
ZStack {
HStack {
HStack {
Button(action: {
}) {
Image(systemName: "arrowtriangle.left.fill")
}
}
Spacer()
HStack {
Button(action: {
}) {
Image(systemName: "arrowtriangle.right.fill")
}
}
}
HStack {
Text("Title")
DatePicker("Date", selection: $currentDate, displayedComponents: [.date])
}
}
}
}
My Center Item are a Text and a DatePicker, everything works as expected until the date picker is placed. The title of DatePicker is placed on the left and date is placed on the right.
Without the DatePicker
With the DatePicker
Any idea to solve this beautifully so that a Text and a DatePicker are close on the center while there are two HStacks that are adjested to on the left and right
Add .fixedSize() to the HStack containing the Text view and DatePicker:
struct ContentView: View {
#State private var currentDate = Date()
var body: some View {
ZStack {
HStack {
HStack {
Button(action: {
}) {
Image(systemName: "arrowtriangle.left.fill")
}
}
Spacer()
HStack {
Button(action: {
}) {
Image(systemName: "arrowtriangle.right.fill")
}
}
}
HStack {
Text("Title")
DatePicker("Date", selection: $currentDate, displayedComponents: [.date])
}
.fixedSize() // here
}
}
}
or add .fixedSize() to the DatePicker.

Closing A View From Another View

I am still learning SwiftUI and I have come across a small problem.
In my app, I have a main view. On the top is a search bar and at the bottom, a menu with different buttons. I want to change views when clicking those buttons. However, I only want to change the middle section.
No big deal, I will just put the middle part into a NavigationView. That works alright and I am able to change my views. My problem is that the buttons below do not have any impact on the new view.
To try to simplify: Let’s say I’m on home page. I then click the grocery list button (guess what I’m making school projects lol). My navigation link works just fine and goes to the list. So, now I’m on view 2 let’s say. When I press the home button, it doesn’t close that view and go to my main one. Here is my code setup:
import SwiftUI
struct ContentView: View {
#State private var searchText: String = ""
#State private var action: Int? = 0
var body: some View {
ZStack {
// Top Menu
VStack{
HStack {
Spacer()
TextField("Search",
text: $searchText)
.background(Color.white)
Button(action: {
self.action = 1
}, label: {
Image(systemName: "magnifyingglass.circle")
.font(.largeTitle)
})
Spacer()
}
// Body
NavigationView {
VStack {
Text("Can I See Something")
NavigationLink(destination: SearchView(), tag: 1, selection: $action) {
}
Text("Yes/No")
}
}
Spacer()
// Bottom Menu
HStack (alignment: .top) {
Spacer()
VStack {
Button(action: {
}, label: {
Image(systemName: "house.fill")
.font(.largeTitle)
})
.padding(.top)
Text("Home")
}
Divider()
.padding(.horizontal)
.frame(width: 2.5, height: 100)
VStack {
Button(action: {
}, label: {
Image(systemName: "newspaper")
.font(.largeTitle)
})
.padding(.top)
Text("Weekly\nAd")
.multilineTextAlignment(.center)
}
Divider()
.padding(.horizontal)
.frame(width: 2.5, height: 100)
VStack {
Button(action: {
}, label: {
Image(systemName: "checklist")
.font(.largeTitle)
})
.padding(.top)
Text("Grocery\nList")
.multilineTextAlignment(.center)
}
Divider()
.padding(.horizontal)
.frame(width: 2.5, height: 100)
VStack {
Button(action: {
}, label: {
Image(systemName: "person.crop.circle")
.font(.largeTitle)
})
.padding(.top)
Text("Account")
}
Spacer()
}
}
}
}
}
struct SearchView: View {
var body: some View {
ZStack {
Text("Nothing to see here!")
}
.navigationBarBackButtonHidden(true)
}
}
SearchView is a separate view (in its own file) in the app that opens up when the magnifying glass button is pressed. Currently it does not do anything. However I want to be able to press those buttons on this view above to still navigate the app.
Also, on another note, is there anyway to get rid of the back button?
In your code the buttons do not have any function.
Instead of creating a tab bar on your own, I'd rather take something like:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
MainView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
NewsView()
.tabItem {
Label("Weekly\nAd", systemImage: "newspaper")
}
OrderView()
.tabItem {
Label("Grocery\nList", systemImage: "checklist")
}
AccountView()
.tabItem {
Label("Account", systemImage: "person.crop.circle")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct MainView: View {
var body: some View {
Text("Home View")
}
}
struct NewsView: View {
var body: some View {
Text("News View")
}
}
struct OrderView: View {
var body: some View {
Text("Order View")
}
}
struct AccountView: View {
var body: some View {
Text("Account View")
}
}
In that case you'll have to create a view for each tab you are configuring (see the last 4 structs).
If you want to do it with a Stack with your own created buttons, I think you should create al 4 views as well and then you either hide them or put them out of focus by using an offset. In that case the buttons should hide/show the specific views or change the offset accordingly to move the specific views into the visible area. With the offset you also can add some animation.
Regarding the search bar on top of your app, since the views are all different, I wouldn't keep the same search bar everywhere, but if you really want to have it that way, you can embed the code + your search bar into a VStack (as you did it in your example).

Navigationlink question in Xcode 13.1 -- Blanks instead of links?

Sorry for the newbie question, but I'm stuck on why Navigationlink produces no links at all. Xcode compiles, but there's a blank for where the links to the new views are. This particular view is View 3 from ContentView, so the structure is ContentView -> View 2 -> View 3 (trying to link to View 4).
struct MidnightView: View {
var hourItem: HoursItems
#State var showPreferencesView = false
#State var chosenVersion: Int = 0
#State var isPsalmsExpanded: Bool = false
#State var showLXX: Bool = false
var body: some View {
ScrollView (.vertical) {
VStack (alignment: .center) {
Group {
Text (hourItem.hourDescription)
.font(.headline)
Text ("Introduction to the \(hourItem.hourName)")
.font(.headline)
.bold()
.frame(maxWidth: .infinity, alignment: .center)
ForEach (tenthenou, id: \.self) {
Text ("\($0)")
Text ("\(doxasi)")
.italic()
}
}
.padding()
NavigationView {
List {
ForEach (midnightHours, id:\.id) {watch in
NavigationLink ("The \(watch.watchName)", destination: MidnightWatchView (midnightItem: watch, chosenVersion: self.chosenVersion, isPsalmsExpanded: self.isPsalmsExpanded, showLXX: self.showLXX))
}
}
}
Group {
Text ("Absolution of the \(hourItem.hourName)")
.font(.headline)
Text (absolutionTexts[(hourItem.hourName)] ?? " ")
Divider()
Text ("Conclusion of Every Hour")
.font(.headline)
Text (hourConclusion)
Divider()
Text (ourFather)
}
.padding()
}
}
.navigationBarTitle ("The Midnight Hour", displayMode: .automatic)
.navigationBarItems (trailing: Button (action: {self.showPreferencesView.toggle()}) {Text (psalmVersions[chosenVersion])}
.sheet(isPresented: $showPreferencesView) {PreferencesView(showPreferencesView: self.$showPreferencesView, chosenVersion: self.$chosenVersion, isPsalmsExpanded: self.$isPsalmsExpanded, showLXX: self.$showLXX)})
}
}
The cause of the NavigationLink not appearing is probably due to the fact that you're including a List within a ScrollView. Because List is a scrolling component as well, the sizing gets messed up and the List ends up with a height of 0. Remove the List { and corresponding } and your links should appear.
There are a number of other potential issues in your code (as I alluded to in my comment), including a NavigationView in the middle of a ScrollView. I'd remove that as well, as you probably have a NavigationView higher up in your view hierarchy already.

Navigation repeats itself several times after clicking the object

I just shared this Bug with Apple. I want to share with you.
Application Follow
1 - After the user logs on to the onBoardingView page, they are directed to ContentView with fullScreenCover.
2 - ContentView page contains objects in TabView that are repeated with ForEach. Clicking on these objects will take you to the DetailView page.
3 - However, Navigation repeats itself several times after clicking the object.
My English is bad. Sorry for this.
Video is here
Project file is here
struct OnboardView: View {
#State var isLogin: Bool = false
var body: some View {
Button(action: {self.isLogin = true}) {
Text("Login")
}
.fullScreenCover(isPresented: self.$isLogin) {
ContentView()
}
}
}
struct ContentView: View {
#State var selected: String = ""
var items: [String] = ["1","2","3","4","5","6","7","8","9","10"]
var body: some View {
NavigationView {
TabView(selection: $selected) {
ForEach(items, id: \.self) { item in
NavigationLink(
destination: DetailView(),
label: {
Text(item)
.foregroundColor(.white)
.padding()
.background(Color.orange)
.cornerRadius(10)
})
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
}
When working with ForEach in SwiftUI, you have to be extra careful on the ids.
Try changing items to items.indices instead:
ForEach(items.indices, id: \.self) { item in
NavigationLink(
destination: Text("Detail View"),
label: {
Text(items[item])
.foregroundColor(.white)
.padding()
.background(Color.orange)
.cornerRadius(10)
}
)
}

SwiftUI NavigationButton without the disclosure indicator?

When making a List with a row that pushes to a new view, SwiftUI adds a disclosure indicator ">" automatically? How do I remove it if I don't want it?
NavigationView {
List {
NavigationButton(destination: DetailView()) {
ListItem()
}
}
.navigationBarTitle(Text("Some title"))
}
On a UITableViewCell you set Accessory to None but how do I do that in SwiftUI?
Setting the NavigationLink width and hiding it did the trick for me
List {
ForEach(pages) { page in
HStack(spacing: 0) {
Text("Something")
NavigationLink(destination: Text("Somewhere")) {
EmptyView()
}
.frame(width: 0)
.opacity(0)
}
}
}
Swift 5, Xcode 11. ZStack works perfect.
var body: some View {
NavigationView {
List {
ForEach(viewModel.currenciesViewModel) { cellViewModel in
ZStack {
cellViewModel.makeView()
NavigationLink(destination: ChooseCurrencyListView()) {
EmptyView()
}
.buttonStyle(PlainButtonStyle())
}
}
}
.navigationBarHidden(true)
.navigationBarTitle("", displayMode: .inline)
}
}
The easiest one. The content for each item in the list.
ZStack {
NavigationLink(destination: DetailView()) {
EmptyView()
}.hidden()
RowView()
}
As workaround I can suggest to add .padding modifier like this:
NavigationView {
List {
NavigationButton(destination: DetailView()) {
ListItem()
}
}
.navigationBarTitle(Text("Some title"))
}
.padding(.trailing, -32.0)
So you will get rows without visible disclosure:
You can also put it in the .background modifier:
List {
Text("Go to...")
.background(NavigationLink("", destination: Text("Detail View")))
}
If you already have the background modifier on the Text, you can wrap the Text in a HStack and apply background to the HStack.
What you can do, if you are using list, is setting the navigationlink to hidden and its frame width to zero.
HStack{
Button(action: {self.statusShow = 1}, label: {
Image(systemName: "info.circle")
})
NavigationLink(destination: StimulatorSettingView(),
tag: 1,
selection: self.$statusShow){
EmptyView()
}.hidden().frame(width: 0)
}
This worked for me.
As of beta 6, this works well:
struct SwiftUIView: View {
var body: some View {
NavigationView {
List {
HStack {
Text("My Cell Content")
NavigationLink(destination: Text("destination"), label: {
EmptyView()
})
}
}
}
}
}
You don't have to use NavigationLink to wrap your Label directly. It will work as long as the link is anywhere in your view hierarchy.
Here I've wrapped it in a button, which allows you to trigger an action prior to pushing the view. Since the NavigationLink has an EmptyView for the label the disclosure indicator is not visible. You can also style this with ButtonStyle.
struct NavigationButton<Destination: View, Label: View>: View {
var action: () -> Void = { }
var destination: () -> Destination
var label: () -> Label
#State private var isActive: Bool = false
var body: some View {
Button(action: {
self.action()
self.isActive.toggle()
}) {
self.label()
.background(NavigationLink(destination: self.destination(), isActive: self.$isActive) {
EmptyView()
})
}
}
}
And to use it:
NavigationButton(
action: { print("tapped!") },
destination: { Text("Pushed View") },
label: { Text("Tap me") }
)
NavigationLink is what we should define in a scope enclosed inside a NavigationView.
But when we use NavigationLink it is attached to the enclosing view, so to reuse the same NavigationLink with other views, we use tag which differentiates between different Destinations.
struct SwiftUIView: View {
#State private var viewState: Int? = 0
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("View 1"), tag: 1, selection: $viewState) {
EmptyView()
}
NavigationLink(destination: Text("View 2"), tag: 2, selection: $viewState) {
EmptyView()
}
Text("First View")
.onTapGesture {
self.viewState = 1
}
Text("Second View")
.onTapGesture {
self.viewState = 2
}
}
}
}
}
Here we bind a Hashable property with all the NavigationLinks present in our VStack so that when a particular View is tapped we can notify which Destination should be opened by setting the value of Bindable property.
If we don't notify the correct Destination by setting the value of tag, always the View defined inside the Closure of NavigationLink will be clickable and nothing else.
Using this approach you don't need to wrap all your clickable views inside NavigationView, any action on any view can use any NavigationLink just by setting the tag.
Thanks, hope this helps.
Works well for me!
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
LandmarkRow(landmark: landmark)
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
EmptyView()
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE", "iPhone 11 Pro Max"], id: \.self) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
.previewDisplayName(deviceName)
}
}
}
Use .frame(width: 0).opacity(0.0):
NavigationView {
List {
ForEach(options) {
option in
ZStack {
YourView(option: option)
NavigationLink(destination: ProductListView(),
label: {
EmptyView()
}).frame(width: 0).opacity(0.0)
}.listRowInsets(EdgeInsets())
}
}.navigationBarHidden(true)
}
My version of this solution is to make a view modifier. I think it's the cleanest way, as it doesn't use AnyView.
Note that this solution runs the init() for the destination when it draws the element the .navigationLink() is attached to.
Usage
Text("Link")
.navigationLink({
// put your destination here
})
How To
import SwiftUI
extension View {
func navigationLink<Destination: View>(_ destination: #escaping () -> Destination) -> some View {
modifier(NavigationLinkModifier(destination: destination))
}
}
fileprivate struct NavigationLinkModifier<Destination: View>: ViewModifier {
#ViewBuilder var destination: () -> Destination
func body(content: Content) -> some View {
content
.background(
NavigationLink(destination: self.destination) { EmptyView() }.opacity(0)
)
}
}
This helps to push and pass the model to the next navigation view controller.
struct ContentView : View {
#State var model = PostListViewModel()
var body: some View {
NavigationView {
List(model.post) { post in
ListCell(listData: post)
}.navigationBarTitle(Text("My Post"))
}
}
}
struct ListCell: View {
var listData: Post
var body: some View {
return NavigationButton(destination: DetailContentView(post: listData)) {
HStack {
ImageRow(model: listData) // Get image
VStack(alignment: .leading) {
Text(listData.login).font(.headline).lineLimit(nil)
Text(listData.url).font(.subheadline).lineLimit(nil)
}.padding(.leading, 10)
}.padding(.init(top: 5, leading: 0, bottom: 5, trailing: 0))
}
}
}
Here's a reusable "plain" navigation link view (i.e. without the chevron disclosure indicator) that can be a drop-in replacement for NavigationLink:
struct PlainNavigationLink<Label, Destination>: View where Label: View, Destination: View {
#ViewBuilder var destination: () -> Destination
#ViewBuilder var label: () -> Label
var body: some View {
label()
.background(
NavigationLink(destination: destination, label: {})
.opacity(0)
)
}
}
To use it, simply replace NavigationLink with PlainNavigationLink:
NavigationView { // or NavigationStack in iOS 16
List {
ForEach(1...30, id: \.self) { _ in
PlainNavigationLink {
Text("Hello, world!")
} label: {
Text("Hello, world!")
}
}
}
}
We can also extend it with convenience initializers for LocalizedStringKey and String, just like NavigationLink does.
just came here looking for the answer to this question, but none of the proposed solutions worked for me (can't have an empty view, because i want to put something in the list row; i'm already messing with the padding (and increasing trailing padding didn't seem to work) ... i was about to give up, and then something occurred to me: what if you crank up the z-index of the list row itself? seemed somewhat unlikely, but i gave it a try and, i'll be damned, it worked! i was so pleasantly surprised, i felt like sharing ...
e.g.:
// in body of your list row view
HStack(alignment: .top, spacing: 0.0) {
// stuff ...
}
.zIndex(9999999999)
If you need children behaviour for List and NavigationLink, without additional discloser in the same time, I want to promote this tricky solution, main point at HStack
var body: some View {
NavigationView {
List(items, children: \.items) { item in
ZStack {
NavigationLink(destination: DetailsView()) {
EmptyView()
}.hidden()
HStack {
RowView(item: item)
Spacer()
}
}
}
}
}
Once you put your button in a scrollview, the disclosure button will be hidden. Just make sure to disable your scroll indicator.
there is no documentation yet, so you can use ScrollView for now
NavigationView {
ScrollView {
ForEach(0...100){ x in
NavigationButton(destination: Text("ss")) {
HStack {
Text(String(x))
Spacer()
}
.padding()
.background(Color.white)
.shadow(radius:1,y:1)
}
}
.frame(width: UIScreen.main.bounds.width - 32)
.padding()
}
}
Removing List and just using ForEach works fine with navigation link. You just have to create your own list row. This works for me
NavigationView {
ForEach(pages) {
page in
NavigationLink(destination: DetailView()) {
ListItem()
}
}
}