Can you access Picker elements during runtime and change their color - swift

I want to change the color of the current selected Element of the Picker. Is this possible? This is my code.
Picker("Select a Project", selection: $selectedProjectString){
ForEach(projects, id: \.self) {
Text($0).lineLimit(1).frame(height:120)
}
}.foregroundColor(Color.white)
.frame(height: 120)
The element that matches selectedProjectString should be a different color than all the others. Or is it possible to access specific elements like with an index or something?

I came up with this solution:
Picker("Select a Project", selection: $selectedProjectString){
ForEach(projects, id: \.self) {
if (startedProject == $0) {
Text($0).lineLimit(1).frame(height:120).foregroundColor(Color.red)
} else {
Text($0).lineLimit(1).frame(height:120)
}
}
}.foregroundColor(Color.white)
.frame(height: 120)
I check if the selected element equals some value and if, I change the style of the Text object it belongs.
Because i change the value of the variable, the view gets reloaded and it refreshes my picker. Now the selected element has color.

Related

How do you add a view to the end of a multi-line Text view?

I have a Text view that is dynamic, and can sometimes be a long name that spans 2 or 3 lines. How can I add a view immediately next the last word of a multi-line Text view?
How can I move Age (23) immediately to the right of "last-name" ?
HStack(alignment: .bottom) {
Text("First Middle hyphenated-long-last-name")
Text("Age (\(age))")
.font(.caption2)
}
Add a plus(+) sign between the Text views. This will concatenate the Text views while keeping each Text view's unique formatting.
var body: some View {
HStack(alignment: .bottom) {
Text("First Middle hyphenated-long-last-name") +
Text(" Age (\(age))")
.font(.caption2)
}
}
Examples with different frame widths:
...and the HStack or other grouping is not needed when concatenating unless additional group formatting is needed.
If you don’t mind the age being the same size as the name, you can just put them in the same Text view:
HStack(alignment: .bottom) {
Text("First Middle hyphenated-long-last-name" + " Age (\(age))")
}

Unable to control SwiftUI macOS list selection styling

On macOS running natively (not in catalyst mode), a SwiftUI List with selection enabled has multiple style states controlled by what appear to be implicit variables that I can't seem to access. As a result, a custom foregroundColor on a View in a List behaves erratically. In particular, given the below example, there should in theory be 3 total styling states, but in reality there are effectively 5 possible styling states of Item 2:
State
Foreground color
Background color
Screenshot
A. Item 2 is selected and window is active
White
Accent
B. Item 2 is selected and window is inactive
*Black (but should be faded blue)
Gray
C. Item 2 is not selected and window is active (Item 2 also looks the same for an inactive window)
Blue
None
D. Item 2 was just clicked, but we need to wait ~300ms before it becomes selected
*Blue (but should be white)
Accent
E. Item 2 was previously selected, a new item is clicked, but we need to wait ~300ms before the new item becomes selected
*Black (but should be blue)
None
How can I control the foreground color in states B, D, and E? For cases D and E, it seems that there's some kind of built in debouncing on the macOS List selection that causes a brief delay after first clicking before actually becoming selected. Is there something like a not-debounced isHighlighted property? Clearly the built in system is using something like this as the non-custom list label colors immediately switch from black to white regardless of the debounce, as in Item 1 in state 5 above. For case B perhaps there's a different color property instead of foregroundColor that I need to use?
Any suggestions are much appreciated!
Minimally reproducable example (run on macOS native, not catalyst):
#main
struct ExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
#State private var selected: String?
var body: some View {
NavigationView {
List {
NavigationLink(destination: Text("Detail 1"), tag: "1", selection: $selected) {
Label("Item 1", systemImage: "tag")
}
NavigationLink(destination: Text("Detail 2"), tag: "2", selection: $selected) {
Label {
Text("Item 2")
.foregroundColor(selected == "2" ? nil : .blue)
} icon: {
Image(systemName: "tag")
.foregroundColor(selected == "2" ? nil : .blue)
}
}
}
.toolbar {
Button {
} label: {
Image(systemName: "sidebar.left")
}
}
}
.navigationTitle("Test")
.listStyle(.sidebar)
}
}
Style state screenshots above all come from this example:

toolbar text item gets cropped

There is a very weird behavior happening with the toolbar, I have the following:
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
Imagegoeshere...
.frame(width: 20, height: 20)
Text("Polkadot")
// Text(coinInfo?.name ?? "-")
}
}
}
Just like that it displays correct the image and on the right the name "Polkadot" (that's for testing), if I replace that Text("Polkadot") with the real value (which contains the exact text with no spaces) it crops it: Text(coinInfo?.name ?? "-")
This is how it looks with the testing text:
and this is how it looks with the real value yet the same exact text:
Any idea what could be causing this?
By accident just now I found the solution, still I have no idea why this happens, this is how it got fixed:
Replace the HStack with LazyHStack

Using a "Plus" button that will add a new Picker field on the screen in Swift

First off, thanks for taking the time to look at this, you folks rock!
I am a teacher for the blind/visually impaired by day and have just started dabbling in code in order to create some neat tools to advance our profession.
The first app I am trying to build is an evaluation tool. I have been able to use Forms with Pickers and Toggles to accomplish this fairly successfully with a lot learning along the way.
The biggest problem I am having is when recording their current visual diagnosis. Most of our kids have multiple diagnosis so I needed a way for the user to add as many as they need for each kid. With the help of #aheze's reply in https://stackoverflow.com/a/69137065/18850386 and a little modifying, I have been able to create the Button I want using a ForEach statement but the selected Picker values are tied together. Here is my current code and picture.
Screenshot of current code preview
#State var eyeConditions = [""]
#State var eyeConditionsList = ""
var body: some View {
NavigationView {
Form {
Section(header: Text("Active Eye Condition(s)")) {
ForEach(eyeConditions.indices, id: \.self) { index in
Picker(
selection: $eyeConditionsList,
label: Text("Selected Condition:"),
content: {
Text("").tag("1")
Text("Amblyopia").tag("2")
Text("Aphakia").tag("3")
Text("Astigmatism").tag("4")
Text("Bulls Eye Maculopathy").tag("5")
Text("Cataract").tag("6")
Text("Coloboma").tag("7")
Text("Color Blindness").tag("8")
Text("Convergence Insufficiency").tag("9")
Text("Corneal Scarring").tag("10")
})
}
Button(action: {
eyeConditions.append("")
}) {
Image(systemName: "plus.circle")
.foregroundColor(Color.blue)
}
}
}
.navigationBarTitle("Visual Information")
}
}
My question is, how do I make it to where each newly created Picker value is not tied to each other and displays as separate values?
Thanks in advance, I truly appreciate your time and help!
Declare eyeConditionsList also as array
#State var eyeConditionsList = [""]
In the button action append also an item to eyeConditionsList
Button(action: {
eyeConditions.append("")
eyeConditionsList.append("")
Bind selection to the appropriate index
Picker(
selection: $eyeConditionsList[index]
But in practice you need only one #State property
#State var eyeConditions = [""]
var body: some View {
NavigationView {
Form {
Section(header: Text("Active Eye Condition(s)")) {
ForEach(eyeConditions.indices, id: \.self) { index in
Picker(
selection: $eyeConditions[index],
label: Text("Selected Condition:"),
content: {
Text("").tag("1")
Text("Amblyopia").tag("2")
Text("Aphakia").tag("3")
Text("Astigmatism").tag("4")
Text("Bulls Eye Maculopathy").tag("5")
Text("Cataract").tag("6")
Text("Coloboma").tag("7")
Text("Color Blindness").tag("8")
Text("Convergence Insufficiency").tag("9")
Text("Corneal Scarring").tag("10")
})
}
Button(action: {
eyeConditions.append("")
}) {
Image(systemName: "plus.circle")
.foregroundColor(Color.blue)
}
}
}

SwiftUI beta 7: Trigger `List` to scroll when item added?

Using Xcode 11 beta 7 and Catalina beta 19A536g (6?)
In my SwiftUI app I have a simple view with a list. Below the list I have a button to add items to the list.
After having added some items, the newly added items are not visible, since they are outside the content size of the list.
var body: some View {
NavigationView {
VStack {
List(self.accounts) { account in
Text("\(account.name)")
}
Button("Add new account") {
self.addNewAccount()
}
}.navigationBarTitle("Select account")
}
}
I guess I would like some binding the content offset of the list, passed to my method addNewAccount and trigger a scrolling of the list.
Can I somehow programmatically trigger the list to scroll down to the new content?
the easiest way to achieve it is to flip the list and its content using .scaleEffect(x: 1, y: -1, anchor: .center) in order to have an upside down structured list but with the correct looking content therefore, insertion of item at index 0 in the list will be performed at the bottom with a nice looking animation
List {
ForEach(self.content) { itemContent in
Item(itemContent).scaleEffect(x: 1, y: -1, anchor: .center)
}
}.scaleEffect(x: 1, y: -1, anchor: .center)