AdvancedList – listview wrapper – loading state, error, pagination
  • July 22, 2025

This package provides a wrapper view around the SwiftUI List view which adds pagination (through my ListPagination package) and an emptyerror and loading state including a corresponding view.

📦 Installation


 

Add this Swift package in Xcode using its Github repository url. (File > Swift Packages > Add Package Dependency…)

🚀 How to use


 

The AdvancedList view is similar to the List and ForEach views. You have to pass data (RandomAccessCollection) and a view provider ((Data.Element) -> some View) to the initializer. In addition to the List view the AdvancedList expects a list state and corresponding views. Modify your data anytime or hide an item through the content block if you like. The view is updated automatically 🎉.

import AdvancedList

@State private var listState: ListState = .items

AdvancedList(yourData, content: { item in
Text(“Item”)
}, listState: listState, emptyStateView: {
Text(“No data”)
}, errorStateView: { error in
Text(error.localizedDescription)
.lineLimit(nil)
}, loadingStateView: {
Text(“Loading …”)
})

🆕 Custom List view

 

Starting from version 6.0.0 you can use a custom list view instead of the SwiftUI List used under the hood. As an example you can now easily use the LazyVStack introduced in iOS 14 if needed.

Upgrade from version 5.0.0 without breaking anything. Simply add the listView parameter after the upgrade

AdvancedList(yourData, listView: { rows in
if #available(iOS 14, macOS 11, *) {
ScrollView {
LazyVStack(alignment: .leading, content: rows)
.padding()
}
} else {
List(content: rows)
}
}, content: { item in
Text(“Item”)
}, listState: listState, emptyStateView: {
Text(“No data”)
}, errorStateView: { error in
Text(error.localizedDescription)
.lineLimit(nil)
}, loadingStateView: {
Text(“Loading …”)
})

🆕 Custom Content view

 

Starting from version 8.0.0 you have full freedom & control over the content view rendered in the items state of your AdvancedList. Use a SwiftUI List or a custom view.

Upgrade from version 7.0.0 without breaking anything and use the new API:

AdvancedList(listState: yourListState, content: {
VStack {
Text(“Row 1”)
Text(“Row 2”)
Text(“Row 3”)
}
}, errorStateView: { error in
VStack(alignment: .leading) {
Text(“Error”).foregroundColor(.primary)
Text(error.localizedDescription).foregroundColor(.secondary)
}
}, loadingStateView: ProgressView.init)

📄 Pagination

 

The Pagination functionality is now (>= 5.0.0) implemented as a modifier. It has three different states: erroridle and loading. If the state of the Pagination changes the AdvancedList displays the view created by the view builder of the specified pagination object (AdvancedListPagination). Keep track of the current pagination state by creating a local state variable (@State) of type AdvancedListPaginationState. Use this state variable in the content ViewBuilder of your pagination configuration object to determine which view should be displayed in the list (see the example below).

If you want to use pagination you can choose between the lastItemPagination and the thresholdItemPagination. Both concepts are described here. Just specify the type of the pagination when adding the .pagination modifier to your AdvancedList.

The view created by the content ViewBuilder of your pagination configuration object will only be visible below the List if the last item of the List appeared! That way the user is only interrupted if needed.

Example:

@State private var paginationState: AdvancedListPaginationState = .idle

AdvancedList(…)
.pagination(.init(type: .lastItem, shouldLoadNextPage: {
paginationState = .loading
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
items.append(contentsOf: moreItems)
paginationState = .idle
}
}) {
switch paginationState {
case .idle:
EmptyView()
case .loading:
if #available(iOS 14, *) {
ProgressView()
} else {
Text(“Loading …”)
}
case let .error(error):
Text(error.localizedDescription)
}
})

📁 Move and 🗑️ delete items

 

To enable the move or delete function just use the related onMove or onDelete view modifier. Per default the functions are disabled if you don’t add the view modifiers.

import AdvancedList

@State private var listState: ListState = .items

AdvancedList(yourData, content: { item in
Text(“Item”)
}, listState: listState, emptyStateView: {
Text(“No data”)
}, errorStateView: { error in
Text(error.localizedDescription)
.lineLimit(nil)
}, loadingStateView: {
Text(“Loading …”)
})
.onMove { (indexSet, index) in
// move me
}
.onDelete { indexSet in
// delete me
}

🎛️ Filtering

 

You can hide items in your list through the content block. Only return a view in the content block if a specific condition is met.

🎁 Example


 

The following code shows how easy-to-use the view is:

import AdvancedList

@State private var listState: ListState = .items

AdvancedList(yourData, content: { item in
Text(“Item”)
}, listState: listState, emptyStateView: {
Text(“No data”)
}, errorStateView: { error in
VStack {
Text(error.localizedDescription)
.lineLimit(nil)

Button(action: {
// do something
}) {
Text(“Retry”)
}
}
}, loadingStateView: {
Text(“Loading …”)
})

For more examples take a look at the Example directory.

GitHub


View Github

#tableview #taglistview
YOU MIGHT ALSO LIKE...
SwiftSpeech

Recognize your user's voice elegantly without having to figure out authorization and audio engines. SwiftSpeech Examples Features Installation Getting Started ...

SwiftUIValueSlider

Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements iOS 14.0 Installation ...

Sliders

Sliders is a compilation of all my stylable drag based SwiftUI components. It provides a variety of unique controls as well ...

SlidingRuler

SlidingRuler is a Swift package containing a SwiftUI control that acts like an linear infinite slider or a finite, more precise ...

Skeletonui

SkeletonUI aims to bring an elegant, declarative syntax to skeleton loading animations. Get rid of loading screens or spinners and ...