Johno2110
Johno2110

Reputation: 1131

Sticky footer in List SwiftUI

I am trying to implement a sticky footer in a List View in SwiftUI

It doesn't seem to operate the same as the header per say. This is an example of a sticky header implementation

     List {
      ForEach(0..<10) { index in
        Section(header: Text("Hello")) {
          ForEach(0..<2) { index2 in
            VStack {
              Rectangle().frame(height: 600).backgroundColor(Color.blue)
            }
          }
        }.listRowInsets(EdgeInsets())
      }
    }

This above gives a sticky header situation. Although, once I change Section(header: ... to Section(footer:... it doesn't seem to be sticky anymore, it's simply places at the end of the row.

A more explicit reference

 List {
  ForEach(0..<10) { index in
    Section(footer: Text("Hello")) {
      ForEach(0..<2) { index2 in
        VStack {
          Rectangle().frame(height: 600).backgroundColor(Color.blue)
        }
      }
    }.listRowInsets(EdgeInsets())
  }
}

Does anyone have any solutions for this?

Upvotes: 9

Views: 11412

Answers (3)

Douglas Frari
Douglas Frari

Reputation: 4377

Swift 5 / 2023 / iOS 16

List {
...
}
.toolbar {
  ToolbarItemGroup(placement: .bottomBar) {
     Text("App iOS Version 1.0.0 (xyz)")
         .font(.footnote)
         .foregroundColor(.secondary)
         .frame(maxWidth: .infinity)
         .textSelection(.enabled)
     }
}

enter image description here

Upvotes: 10

TruMan1
TruMan1

Reputation: 36078

You can use overlay on the List:

struct ContentView: View {
    @State private var selectedTab = 0

    var body: some View {
        TabView(selection: $selectedTab) {
            VStack {
                List {
                    ForEach(0..<20, id: \.self) { _ in
                        Section {
                            Text("Item 1")
                            Text("Item 2")
                            Text("Item 3")
                        }
                    }
                }
                .listStyle(InsetGroupedListStyle())
                .overlay(
                    VStack {
                        Spacer()
                        Text("Updated at: 5:26 AM")
                            .font(.footnote)
                            .foregroundColor(.secondary)
                            .frame(maxWidth: .infinity)
                    }
                )
            }
            .tabItem {
                Label("First", systemImage: "alarm")
            }
            Text("Content 2")
                .tabItem {
                    Label("Second", systemImage: "calendar")
                }
        }
    }
}

Upvotes: 1

Johno2110
Johno2110

Reputation: 1131

With the latest on SwiftUI (2) we now have access to a few more API's

For starters we can use a LazyVStack with a ScrollView to give us pretty good performance, we can then use the pinnedViews API to specify in an array which supplementary view we want to pin or make sticky. We can then use the Section view which wraps our content and specify either a footer or header.

** This code is working as of Xcode beta 2 **

As for using this in a List I'm not too sure, will be interesting to see the performance with List vs Lazy...

struct ContentView: View {
  var body: some View {
    ScrollView {
      LazyVStack(spacing: 10, pinnedViews: [.sectionFooters]) {
        ForEach(0..<20, id: \.self) { index in
          Section(footer: FooterView(index: index)) {
            ForEach(0..<6) { _ in
              Rectangle().fill(Color.red).frame(height: 100).id(UUID())
            }
          }
        }
      }
    }
  }
}

struct FooterView: View {
  
  let index: Int
  
  var body: some View {
    VStack {
      Text("Footer \(index)").padding(5)
    }.background(RoundedRectangle(cornerRadius: 4.0).foregroundColor(.green))
  }
}


struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

Upvotes: 6

Related Questions