So, I'm in a situation where I have a Picker with two items in it, when a item is pressed there is a effect on the Item, can I turn off that effect?
Picker(selection: $pickerSelection, label: Text("")) {
ForEach(Type.allCases, id: \.self) { type in
Text(type.title)
.tag(type.rawValue)
}
}
.pickerStyle(SegmentedPickerStyle())
Cheers, stay save!
Related
I'm trying to use Picker on .contextMenu of navigationBarItems. However, the behavior is not as I would expect and I can't tell if this is Apple bug or if I'm doing something wrong (XCode 13.4).
After the user selects an item from the dropdown, the variable value do change but reopening the context menu, the wrong item is marked as "selected".
I've created the most basic demo to illustrate it. Same behavior on real device (iPhone 11 / iOS 15.4.1).
struct ContentView: View {
#State private var isAutoRefresh = true
var body: some View {
NavigationView {
Text("Auto refresh is: \(String(isAutoRefresh))")
.navigationBarTitle("Demo")
.navigationBarItems(
trailing:
Button(action: {}, label: {
Image(systemName: "arrow.clockwise")
})
.contextMenu {
Picker(selection: self.$isAutoRefresh, label: Text("")) {
Text("Manual refresh").tag(false)
Text("Auto refresh").tag(true)
}
.pickerStyle(InlinePickerStyle())
}
)
}
}
}
Is this a bug? Is there any workaround I can use?
Context menu is created once and cached, so we need to rebuild it once anything changed outside.
Here is a fix. Tested with Xcode 13.3 / iOS 15.4
.contextMenu {
Picker(selection: self.$isAutoRefresh, label: Text("")) {
Text("Manual refresh").tag(false)
Text("Auto refresh").tag(true)
}
.pickerStyle(InlinePickerStyle())
}.id(isAutoRefresh) // << here !!
Alternate: Just to use Menu instead of Button with context menu (if applicable by design), like
Menu {
Picker(selection: self.$isAutoRefresh, label: Text("")) {
Text("Manual refresh").tag(false)
Text("Auto refresh").tag(true)
}
.pickerStyle(InlinePickerStyle())
} label: {
Image(systemName: "arrow.clockwise")
}
I have a list inside a view. Inside the list, items are iterated through to populate the list. When you click on each list item, I want to navigate to another view.
This is working as expected but I want to have a Button represented by a circle in each list item that can be clicked independently without navigating to the second view. Right now, clicking the circle just takes me to 2nd view. How can I accomplish this?
var body: some View {
NavigationView {
List {
ForEach(items) { item in
NavigationLink(
destination: OtherView(name: "test"),
label: {
Text("Navigate")
})
HStack {
Image("1")
.resizable()
.frame(width: 32.0, height: 32.0)
Button(action: addItem) {
Label("Add Item", systemImage: "circle")
}
}
}
}
}
}
You can not do this with List. You can use VStack or LazyVStack inside a ScrollView as an alternative solution
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
I have a view with hidden navigation bar, but I need to show the navigation bar with back button when user select a value from picker.
When I add a leading button, my code shows all country texts as one item instead of making each Text in separate selectable row.
Any idea how to fix this issue?
VStack{
Form {
Picker(selection: $selectedCountry, label: HStack {
Text("Country")
}) {
ForEach(0 ..< countries.count) {
Text(self.countries[$0])
}
.navigationBarItems(leading: BackButton())
.navigationBarBackButtonHidden(true)
.navigationBarHidden(false)
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(false)
}
}.navigationBarTitle("")
.navigationBarHidden(true)
Applying modifiers to dynamic container, ie. ForEach, you convert it into one view, so picker shows only one combined view.
Here is possible solution - attach needed modifiers only to first item of picker (tested with Xcode 12 / iOS 14)
Form {
Picker(selection: $selectedCountry, label: HStack {
Text("Country")
}) {
ForEach(0 ..< countries.count) {
if 0 == $0 {
Text(self.countries[$0])
.navigationBarItems(leading: BackButton())
.navigationBarBackButtonHidden(true)
.navigationBarHidden(false)
} else {
Text(self.countries[$0])
}
}
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(false)
}
In a SwiftUI view I implemented a vertically scrolling list by creating a VStack that contains a NavigationView that contains some text. I build this by looping through a popularFeedTypes object creating a NavigationLink for each item in the popularFeedTypes object. If a user clicks on the NavigationLink the user is pushed to a new view called FeedTypeView. You can see the code below.
VStack{
NavigationView{
List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
NavigationLink(destination: FeedTypeView(feedType: feedType)) {
Text(feedType.feedType)
}.onTapGesture {
print("TAPPED")
}
}
.navigationBarTitle(Text("Discover"), displayMode: .inline)
}
}
The problem I am experiencing is that if I have an onTapGesture action on the NavigationLink, I experience a different behavior from within the simulator depending upon how I click the row. If I click on the text or on the arrow (>) at the right hand side of the row, the onTapGesture fires off but no navigation occurs. If I click on the space between the text and the arrow, onTapGesture does not fire but navigation occurs. If I remove the onTapGesture code, clicking any of the three places causes navigation to occur. So my question is shouldn't navigation occur even with an onTapGesture action existing? Also shouldn't the onTapGesture action fire off regardless of where you click on the row that makes up the NavigationLink?
VStack {
NavigationView{
List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
NavigationLink(destination: FeedTypeView(feedType: feedType)) {
Text(feedType.feedType)
}
.simultaneousGesture(TapGesture().onEnded {
print("TAPPED")
})
.buttonStyle(PlainButtonStyle())
}
.navigationBarTitle(Text("Discover"), displayMode: .inline)
}
}
This should work. use simultaneousGesture on NavigationLink
You can use onAppear to handle tapped event.
VStack {
NavigationView {
List(self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
NavigationLink(
destination: FeedTypeView(feedType: feedType).onAppear { print("TAPPED") }) {
Text(feedType.feedType)
}
}
.navigationBarTitle(Text("Discover"), displayMode: .inline)
}
}
If you want to perform both action and navigation simultaneously you can do this:
VStack{
NavigationView{
List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
NavigationLink(destination: FeedTypeView(feedType: feedType)) {
Text(feedType.feedType)
}
.simultaneousGesture(TapGesture().onEnded{
print("TAPPED")
})
}
.navigationBarTitle(Text("Discover"), displayMode: .inline)
}
}
If you want to do something before your navigation link is triggered, you can initialize a navigation link with tag and selection.
struct someViewName: View {
#State var navigationLinkTriggerer: Bool? = nil
#State var navigationLinkFeedType: FeedType
var body: some View {
VStack {
NavigationLink(destination: FeedTypeView(feedType: navigationLinkFeedType),
tag: true,
selection: $navigationLinkTriggerer) {
EmptyView()
}
NavigationView {
List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
Button(feedType) {
// do all you want here
print("TAPPED")
// then set the navigationLinkTriggerer to value of you navigation link `tag`
// in this case tag is equal to `true`
// this will trigger the navigation link
self.navigationLinkFeedType = feedType
self.navigationLinkTriggerer = true
}
}
.navigationBarTitle(Text("Discover"), displayMode: .inline)
}
}
}
}