I want to display a picker with segmented style inside a form.
Form {
Section {
Picker("Picker", selection: $selectedOption) {
Text("Option 1")
Text("Option 2")
}
.pickerStyle(.segmented)
} header: {
Text("Pick an option")
}
}
The above code embeds the picker in a section and adds some padding around it (see screenshot). This padding and the white section background looks ugly and is not really needed as the picker already pops out of the background. So I want to get rid of this section background and all the paddings to visually lift the picker to the top level.
I found this other Stackoverflow post that suggests to add the following two modifiers to the picker:
.listRowInsets(.init())
.listRowBackground(.secondarySystemBackground) // (I use .clear instead)
That works to a certain extent:
The listRowInsets modifier removes the horizontal padding on the left and on the right.
The listRowBackground modifier clears the section's background color (or makes it indistinguishable from the form's background).
However, the vertical section padding above and below the picker still remains. To illustrate this, I kept the listRowBackground white:
When I make it transparent, the section header has too much spacing with respect to the picker, the extra padding is indicated by the red line on top.
Question:
Is there a (clean) way to get rid of this padding (both horizontally and vertically)?
You cannot get rid of all padding, as the Form cell has a fixed height and the picker is smaller. But you can shift the picker up to correct the distance to the section header (you might have to live with the extra padding below).
either so (seems a litte unclean ;):
.listRowInsets(EdgeInsets(top: -12, leading: 0, bottom: 0, trailing: 0))
or by offset:
Form {
Section {
Picker("Picker", selection: $selectedOption) {
Text("Option 1").tag(1)
Text("Option 2").tag(2)
}
.offset(x: 0, y: -8) // here
.pickerStyle(.segmented)
.listRowInsets(.init())
.listRowBackground(Color.white) // demo only, should be .clear
} header: {
Text("Pick an option")
}
}
Related
I've build a ScrollView which contains 0-3 images and a multiline text field in a VStack. I also added a ScrollViewReader inside the scrollview and use it to scroll to the bottom of the text field upon certain events (user starts typing, image collection changes).
The point is: sometimes it works, sometimes it doesn't. When it does not work I realized, that when I scroll a little bit by hand and then try again (e.g. typing) it works.
Not sure if this is relevant, but ImageOrPlaceholderComponent first shows a placeholder as long as the image within currentEntryImages is nil, and the image after that (both states imply a change to currentEntryImages and should thus result in scrolling to the bottom of the text field).
NavigationStack {
ScrollView {
ScrollViewReader { scrollview in
VStack {
// Attached images.
AnyLayout(VStackLayout(spacing: 2.5)) {
ForEach(values: currentEntryImages) { entryImage in
ImageOrPlaceholderComponent(image: entryImage)
.clipped()
}
}
// Text field for the entry with toolbar.
TextField("...", text: $entryDTO.text, axis: .vertical)
.id(entryTextFieldAnchor)
.multilineTextAlignment(.leading)
.padding()
.focused($mainTextFieldFocused)
.onAppear { mainTextFieldFocused = true }
// Scroll to the bottom of the text field, when the user is typing ...
.onChange(of: entryDTO.text) { _ in
withAnimation {
scrollview.scrollTo(entryTextFieldAnchor, anchor: .bottom)
}
}
// ... or the entry images have changed.
.onChange(of: currentEntryImages) { _ in
withAnimation {
scrollview.scrollTo(entryTextFieldAnchor, anchor: .bottom)
}
}
}
}
}
}
There is list SwiftUI. I am trying to give a dark gray background for the whole screen but there are parts of list which are not changing to dark gray and the show up as pitch black. Here is the code to create list
List{
ForEach(array_Of_Identifiable_structs) { $item in
...RowStruct(varForIdentifiable_struct: $item)
.background(Color.uiColor(.backgroundColor))
}
}
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
.background(Color.uiColor(.backgroundColor))
Also in ...someRowStruct for row, I have changed the background. Here is the body-
var body: some View {
VStack(alignment: .leading){
HStack {
.Text(....)
.padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing:0))
}
.background(Color.uiColor(.backgroundColor))
}
.background(Color.uiColor(.backgroundColor))
}
Here is screenshot, Just check the row at both the ends of row, it is pitch black, need to make it dark gray -
Any suggestion is welcome! Thanks
The ForEach View isn't a for loop it doesn't support indices (it will crash when the last index is removed and you attempt to look up the array using an index doesn't exist) you have to supply an array of Identifiable structs so it can work with the values instead. You just have to make an item that has the data and the row colour already so you don't have to look it up.
I trying to change the color of the chevron indicator that appears on the section headers in a List view likest one shown here:
I tried to do that by setting the tint color on the list view:
List {
...
}
.tint(.red)
...
That is not working.
How can I change the color of that indicator?
You haven't provided much code but some change with accentColor instead of tint
The chevron can't react on any color changing modifiers.
You have to disable standard chevron and use own, custom, (behaviour of the List is the same), like below
HStack {
Text(text)
NavigationLink(destination: Text("D")) { EmptyView() } // disabled !
Image(systemName: "chevron.right") // << custom !!
.foregroundColor(Color.red) // any color !!!
}
I have 2 Text elements in a VStack. They are set to different font size.
How do I get the first glyph of the 2 Text elements to align perfectly left? Is that even possible?
Below is the code snippet:
extension Font {
static let countDownTitle: Font = Font.system(size: 46, weight: .regular, design: .rounded).leading(.tight)
}
struct MyView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Hello!!")
Text("20.49").font(.countDownTitle)
}
}
}
You have a bit of an artificial test going on here. Remember, each character takes up a different amount of room in a proportional font takes up a different amount of room. When they are laid out, they are put in a space that is controlled by the font designer, not us. You can see this is you cycle through different numbers. The 4 is pretty much right on, but the 5 is way off. This is one of those things that your ability to control it is lacking.
While, I am not at all recommending this, you could get perfect alignment like this, using a monospaced font and an .offset():
extension Font {
static let countDownTitle: Font = Font(UIFont.monospacedSystemFont(ofSize: 46, weight: .regular))
}
struct MyView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Hello!!")
Text("50.49").font(.countDownTitle)
.offset(x: -2.2, y: 0)
}
}
}
But, this is really ugly.
The intended goal is a View that expands in height to show all its elements (no scrolling), that can allow its elements to be drag and dropped to re ordered them. I believe a SwiftUI list will support this drag and drop behaviour however when placed in a VStack with other elements, it limits it's height to be the size of one element. I presume these List views aren't intended to be used within another view?
List {
ForEach(viewModel.sections, id: \.self) { section in
HStack {
Text(section.localisedString)
Spacer()
Image(systemName: "line.horizontal.3")
.foregroundColor(ColourPalette.bodyText)
.smallIcon()
}
.background(ColourPalette.background)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.background(ColourPalette.background)
}
.listStyle(PlainListStyle())
.background(ColourPalette.background)
I would also like to hide the separators however this appears to be an ongoing struggling with SwiftUI but even the SideBarListStyle() doesn't work for me.
Does it make more sense to use a VStack() and if so how easily can the reorder on drag drop and classic list side bar items be implemented?
You have tow options :
1) Using List
For placing the VStack with your List , use Section with header / footer, like that it will scroll with the list
List {
Section(header: Text("Your header here")) {
ForEach(viewModel.sections, id: \.self) { section in
HStack {
Text(section.localisedString)
Spacer()
Image(systemName: "line.horizontal.3")
.foregroundColor(ColourPalette.bodyText)
.smallIcon()
}
.background(ColourPalette.background)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.background(ColourPalette.background)
}
}
And for removidng the separator (IOS 13 support):
Adding UITableView.appearance().separatorColor = .clear anywhere in your code before the List appears should work. While this solution removes the separators, note that all List instances will be bound to this style as there’s no official way currently to only remove separators of specific instances. You may be able to run this code in onAppear and undo it in onDisappear to keep styles different.
2) Use VStack / LazyVStack