In SwiftUI, list view by default takes up entire height of the screen and pushes other elements/views to the bottom of the screen. But I want to append some elements/views where the list items exactly end.
You can add spacer() at appropriate places in the VStack or try something like below:
VStack {
CustomView1()
List {
Section(header: HeaderView(), footer: FooterView())
{
ForEach(viewModel.permissions) { permission in
CustomeView2()
}
GeneralView()//add the views at the end of list items
}
}.listStyle(GroupedListStyle())
}
Related
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'm currently using a List with a GroupedListStyle(), and with a .regular horizontalSizeClass (e.g an iPad in landscape mode), this style of List automatically creates some padding to each section, like this:
struct ListView: View {
var body: some View {
List {
Section {
Text("One")
Text("Two")
Text("Three")
}
}.listStyle(GroupedListStyle())
}
}
This is great, I want this. But since I need to display some elements inside the rows with a fixed width, I need to know the actual width of the row inside the List.
I've tried wrapping the List with a GeometryReader, but the width doesn't match the row's width because of the padding around the entire Section.
struct ListView: View {
var body: some View {
GeometryReader { geometry in
List {
Section {
Text("One") // <-- geometry.size.width != Text.width
Text("Two")
Text("Three")
}
}.listStyle(GroupedListStyle())
}
}
}
So I've tried using the PreferenceKey method explained here by putting a GeometryReader in the listRowBackground modifier of the row, but the value is never updated.
Is there a working way to get the size of the parent, without using a GeometryReader around the parent (as it is finnicky on a List, and needs to be specified Height and Width to work properly)?
I've had to resort to a UITableView with style .insetGrouped, implemented with a Representable and used the property layoutMargins that gives exactly the size of the horizontal margins in this size class.
I want to use NavigationView together with the ScrollView, but I am not seeing List items.
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView{
VStack {
Text("Some stuff 1")
List{
Text("one").padding()
Text("two").padding()
Text("three").padding()
}
Text("Some stuff 2")
}
}
}
}
}
All I see is the text. If I remove ScrollView I see it all, but the text is being pushed to the very bottom. I simply want to be able to add List and Views in a nice scrollable page.
The ScrollView expects dimension from content, but List expects dimension from container - as you see there is conflict, so size for list is undefined, and a result rendering engine just drop it to avoid disambiguty.
The solution is to define some size to List, depending of your needs, so ScrollView would now how to lay out it, so scroll view could scroll entire content and list could scroll internal content.
Eg.
struct ContentView: View {
#Environment(\.defaultMinListRowHeight) var minRowHeight
var body: some View {
NavigationView {
ScrollView{
VStack {
Text("Some stuff 1")
List {
Text("one").padding()
Text("two").padding()
Text("three").padding()
}.frame(minHeight: minRowHeight * 3).border(Color.red)
Text("Some stuff 2")
}
}
}
}
}
Just wanted to throw out an answer that fixed what I was seeing very similar to the original problem - I had put a Label() item ahead of my List{ ... } section, and when I deleted that Label() { } I was able to see my List content again. Possibly List is buggy with other items surrounding it (Xcode 13 Beta 5).
I recently started studying ios/swiftui by developing a small application, which has a list of cards to display picture and message loaded from server.
I was using List to hold those cards but the default list 'decoration' (divider, arrow, tapping effect) looks not very good together with my card view. I disable them by adding below code into SceneDelegate:
UITableView.appearance().separatorColor = .clear
UITableViewCell.appearance().selectionStyle = .none
And having some sort of hack to hide the arrow:
List {
ForEach(0..<self.store.data.count, id: \.self) { idx in
NavigationLink(destination: DetailView(item: self.store.data[idx])) {
EmptyView()
}.frame(width: 0).opacity(0)
ItemCard(item: self.store.data[idx])
}
BottomLoader().onAppear {
if self.store.status != .loading {
self.store.load()
}
}
}
But, the problem is that hiding List's selection style and separator color in SceneDelegate applies to all the lists in App, and I do have couple lists (such as the one in settings) need those style.
Then I tried to change the card holder from List to ScrollView but it leads to another trouble, the onAppear callback of last view (BottomLoader) gets called at the same time with ScrollView onAppear gets called.
As far as I understand, onAppear is supposed to be called when view is rendered and shown. List as the item holder, does not have to calculate the full height of all items, that is probably why List renders only the items about to enter screen. But ScrollView does need to know the full height of all items and that is why all the items get rendered.
Below are two small segments to show different behaviors of List and ScrollView:
List {
ForEach(0..<100) { idx in
Text("item # \(idx)").padding().onAppear { print("\(idx) on appear") }
}
}
// only 18 logs printed
And:
ScrollView {
ForEach(0..<100) { idx in
Text("item # \(idx)").padding().onAppear { print("\(idx) on appear") }
}
}
// all 100 logs printed
Is there any way, to let ScrollView acts like List, to render its subviews when they about to enter screen.
Or, is there any way, to disable those default styles to a specific List, not globally?
I'm trying to add two tables with different sizes to one view in SwiftUI. I want both tables be fully expanded and the whole view to scroll as one. For now I only get both tables fixed size and scroll separately.
some View {
VStack {
Text("Table foo")
List(foo { item in Text(item.name) })
Text("Table bar")
List(bar { item in Text(item.name) })
}
}
Tried changing VStack to a ScrollView, it makes things even worse - tables are becoming one liners.
Also tried replacing List() with ForEach() but then I lose features of the List() I actually want.
I think you want one List with multiple ForEach's. Optionally, you could make it a grouped List with multiple sections. Adapted for your sample, the following concept has worked well for me on several occasions:
struct SwiftUIView: View {
var body: some View {
List {
Section(header: Text("Table foo"))
{
ForEach(foo) { item in Text(item.name) }
}
Section(header: Text("Table bar"))
{
ForEach(bar) { item in Text(item.name) }
}
}
.listStyle(GroupedListStyle())
}
}
You can use Form to embed two lists in a scroll view.
Reference: https://developer.apple.com/documentation/swiftui/form .