'contentInset on SwiftUI's List
Solution 1:[1]
My solution to your problem looks similar with Asperi's answer but his answer will not show the Button
at the top of the view since the Button
is at the last section's footer in the Form
. (Button
will not be visible if you don't scroll to bottom.)
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
let stringArray: [String] = [String](repeating: "Example", count: 30)
var body: some View {
ZStack(alignment: .bottom) {
List {
ForEach(0..<stringArray.count) { stringIndex in
Section {
Text(stringArray[stringIndex])
}
if stringIndex == stringArray.count - 1 {
Spacer()
.listRowInsets(EdgeInsets())
.listRowBackground(
colorScheme == .light ?
Color(.secondarySystemBackground) :
Color(.systemBackground)
)
}
}
}
.listStyle(InsetGroupedListStyle())
Button(action: {}) {
Label("ADD NEW ITEM", systemImage: "plus")
}
.foregroundColor(.white)
.font(.headline)
.frame(height: 64)
.frame(maxWidth: .infinity)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal)
}
}
}
Solution 2:[2]
For a floating button, you can use .safeAreaInset
on the List
. The button will stay pinned to the bottom and the list will scroll and give it appropriate padding.
List {
ForEach((0...20), id: \.self) { row in
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit")
}
}
.listStyle(.inset)
.safeAreaInset(edge: .bottom) {
Button {
//Button Action
} label: {
Text("Button")
.font(.title3)
.bold()
.foregroundColor(.white)
.padding()
.background(Color.red)
.cornerRadius(16)
}
}
Solution 3:[3]
Possible simple solution is just to use footer
of last Section.
Below is a standalone demo (of course styles you can tune as you need). Tested with Xcode 12.4 / iOS 14.4
struct DemoButtonInLastSection: View {
let data = Array(repeating: "some", count: 20)
var body: some View {
Form {
ForEach(data.indices, id: \.self) { i in
Section(footer:
Group {
if i == data.count - 1 {
Button(action: {}) {
RoundedRectangle(cornerRadius: 8)
.overlay(
Label("ADD NEW ITEM", systemImage: "plus")
.foregroundColor(.white))
}
.font(.headline)
.frame(height: 64)
.frame(maxWidth: .infinity)
}
}
) {
Text("Item \(i)")
}
}
}
}
}
Solution 4:[4]
You can use .listRowInsets
for defining last row content insets.
Sample code snippet below:
struct AddButtonInLastSection: View {
var data = [[1: [1, 2, 3, 4, 5, 6]], [2: [1, 2, 3, 4, 5, 6]], [3: [1, 2, 3, 4, 5, 6]]]
var body: some View {
VStack {
List {
ForEach(data, id: \.self) { dict in
ForEach(0 ..< dict.keys.count) { i in
Section(header: Text("Item \(dict.keys[dict.index(dict.startIndex, offsetBy: i)])")
) {
ForEach(0 ..< dict.values.count) { j in
ForEach(dict.values[dict.index(dict.startIndex, offsetBy: j)], id: \.self) { k in
if dict.keys[dict.index(dict.startIndex, offsetBy: i)] == 3 {
if k == 6{
Text("Items: \(k) last")
.listRowInsets(.init(top: 16, leading: 20, bottom: 64, trailing: 0))
}else {
Text("Items: \(k)")
}
} else {
Text("Items: \(k)")
}
}
}
}
}
}
}
Button(action: {}) {
RoundedRectangle(cornerRadius: 4)
.overlay(
Label("ADD NEW ITEM", systemImage: "plus")
.foregroundColor(.white))
}
.foregroundColor(Color.red)
.font(.headline)
.frame(height: 64)
.frame(maxWidth: .infinity)
.padding(.init(top: 0, leading: 8, bottom: 0, trailing: 8))
}
}
}
Solution 5:[5]
Overview
- You could add a
toolbar
, that way you don't have to worry about content inset. - The toolbar would always stay on top and contents would scroll below the toolbar
- Inset is automatically taken care of
Screenshot:
Code:
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(0..<100) { index in
Text("Item \(index)")
}
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(action: doSomething) {
RoundedRectangle(cornerSize: CGSize(width: 8, height: 8))
.foregroundColor(.blue)
.overlay(alignment: .center) {
Text("Button")
.foregroundColor(.white)
}
.frame(width: 300, height: 48)
}
}
}
.navigationTitle("Title")
}
}
private func doSomething() {
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Detr01tDave |
Solution 3 | |
Solution 4 | MobileMatrix |
Solution 5 | user1046037 |