SwiftUI Picker iOS 16 not filling available space - ios

I am using the following code (example) to render a SwiftUI Picker on iOS:
let strings: [String] = ["short", "very, ver long string"]
#State var selectedString: String = ""
Form {
Picker("Method", selection: $selectedString) {
ForEach(strings, id: \.self) { string in
Text(string)
}
}
}
In iOS 16 the design of the menu style picker has changed (it now includes 2 small chevrons), which is all good, except it no longer fills the available width (as it did on iOS 15). This results in longer strings flowing onto multiple lines even when this isn't neccessary.
Short String (all fine):
Long String (not so good):
I have tried .fixedSize(), which works to some extend but if the string does in fact need to be on two lines this forces the label to be squished. If I add a background to the Picker, it is clear that it only fills around 1/3 of the available space.
Does anyone have any suggestions?

Separate the label from the Picker and wrap it in a HStack.
Form {
HStack {
// the new label text
Text("Method")
.fixedSize() // give other views in HStack space to grow
// push the external label and Picker to the leading and trailing view edges
Spacer()
Picker("Method", selection: $selectedString) {
ForEach(strings, id: \.self) { string in
Text(string)
}
}
.labelsHidden() // the label is in the Text view
}
}
Hide the Picker label by using the .labelsHidden() modifier.
Use the .fixedSize() modifier on the new Text. This will allow the Picker to expand to fit all its contents.
Use Spacer between Text label and Picker to push both items to the edge.

Related

SwiftUI - Enable Text view to present trailing whitespace

I have a a Text("string") view in SwiftUI that displays two different strings, one much longer than the other. I would like my SwiftUI text view to present both strings as if they were equal in length, so the view remains the same size (I have other dynamic elements on the page that I do not want it affecting).
To handle this, I am padding my shorter string with spaces (" ") until it reaches the length of the larger string. This does not solve my issue - it seems like SwiftUI Text view is ignoring the trailing whitespace and not presenting it on the screen. Is there any way to resolve this?
If you are OK with having the texts occupying the whole width of the parent view, or if you can use .frame(width:) to have a fixed width, you could try the following approach:
VStack {
HStack {
Text("Short")
Spacer()
}
.background(.blue)
HStack {
Text("A very, very long text to show")
Spacer()
}
.background(.yellow)
}
.padding()
You'll see that the blue and yellow areas are the same size.

Text selection breaks scrolling

I'm trying out iOS 15 with Xcode Beta 2, and I'm using the new textSelection feature for Text.
However, if you enable text selection and put the Text objects in a List, and try scrolling on the text, nothing happens. However, disabling the text selection allows scrolling anywhere on the list.
Here is some reproducible code:
struct ContentView: View {
#State var data = (0..<100).map { "Test: \($0)" }
var body: some View {
List(data, id: \.self) { str in
Text(str)
.textSelection(.enabled)
}
}
}
If you try scrolling by moving your finger up on the area with text, nothing happens. However you can still scroll on the white areas.
Disabling text selection fixes this issue.
Are there any possible workarounds?

How can I make a SwiftUI List row background color extend the full width, including outside of the safe area

In a SwiftUI List, how can I make a list row background (set via .listRowBackground()) extend the full width of the view, even under the safe area? E.g. when running in landscape on a wide iPhone (iPhone 12 Pro Max, for example). Currently, the cell appears white on the far left of the cell until the start of the safe area.
Example code:
struct ContentView: View {
var body: some View {
List {
Text("Test")
.listRowBackground(Color(.systemGray3))
}.listStyle(GroupedListStyle())
}
}
This produces a UI as shown below. I would like the grey background of the cell to extend the full width of the device.
I've tried adding .edgesIgnoringSafeArea(.all) to the Text but it makes no difference.
The answer is to put .edgesIgnoringSafeArea([.leading, .trailing]) on the background Color itself, rather than the list item.
struct ContentView: View {
var body: some View {
List {
Text("Test").listRowBackground(
Color(.systemGray3).edgesIgnoringSafeArea([.leading, .trailing])
)
}.listStyle(GroupedListStyle())
}
}

difference between background color for TextField in SwiftUI between macOS and iOS?

I run into an issue I have no idea how to solve. I plan to have a shared code base for macOS and iOS with SwiftUI (as much as possible).
But already with something simple like setting background color for a text field there is a difference
Following code snippet:
struct NewTextField : View
{
#State var d:String = ""
var body: some View
{
HStack(content:
{
TextField("Date: ", text:$d)
.foregroundColor(.black)
.background(Color.green)
/// ... more views
}
}
}
This is simplified; I have multiple textfields on the real application with background colors depending on the content.
on iOS it looks ok; the full textfield background is set to the desired color; on macOS the TextField appear with white background and colored border.
What I'm doing wrong ?
just to leave it not unanswered:
added
.textFieldStyle(PlainTextFieldStyle())
and it create the desired effect
TextField("Date: ", text:$d)
.textFieldStyle(PlainTextFieldStyle())
.foregroundColor(.black)
.background(Color.green)
based on this post: SwiftUI customized text field in OSX

NavigationBarTitle doesn't shrink text with minimumScaleFactor() or allowsTightening()

When using .navigationBarTitle on a NavigationView, adding the modifiers .minimumScaleFactor(0.5) or .allowsTightening(true) has no effect. The text is still cut off and remains same size.
My app displays a reference code and a few other bits of information in the navigation bar title and it fits perfectly on Plus sized iPhones but gets trimmed (...) on the smaller screen ones.
This information is quite vital to the operation of the app and we are already short of screen space so really don't have anywhere else to put this info.
With UIKit, I would have created a special TitleView to replace the title text in the NavigationBar, but that doesn't work in SwiftUI.
Is there any workaround for this?
Example:
struct ContentView: View {
let items = ["Chocolate", "Vanilla", "Strawberry", "Mint Chip",
"Pistachio"]
let title = "A long title that doesn't fit on a standard iPhone"
var body: some View {
NavigationView {
List(items, id: \.self) {
Text($0)
}
.navigationBarTitle(title, displayMode: .inline).minimumScaleFactor(0.5).allowsTightening(true)
}
}
}
ScreenShot from iPhone 8 Plus:
Screenshot from iPhone 8:

Resources