All Projects → crelies → Advancedlist

crelies / Advancedlist

Licence: mit
Advanced List View for SwiftUI with pagination & different states

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Advancedlist

react-native-paginated-listview
A simple paginated react-native ListView with a few customization options
Stars: ✭ 14 (-91.52%)
Mutual labels:  pagination, listview
InfiniteScroll
You can do a Endless scroll in ListView or RecyclerView with simple steps, with a listener for do request to your web service.
Stars: ✭ 28 (-83.03%)
Mutual labels:  pagination, listview
AdvancedList-SwiftUI
MOVED to https://github.com/crelies/AdvancedList | Advanced list with empty, error and loading state implemented with SwiftUI
Stars: ✭ 41 (-75.15%)
Mutual labels:  pagination, listview
React Native Pagination
Animated Pagination For React Native's ListView, FlatList, and SectionList
Stars: ✭ 296 (+79.39%)
Mutual labels:  pagination, listview
Gorm Paginator
gorm pagination extension
Stars: ✭ 136 (-17.58%)
Mutual labels:  pagination
Jsonapi.rb
Lightweight, simple and maintained JSON:API support for your next Ruby HTTP API.
Stars: ✭ 116 (-29.7%)
Mutual labels:  pagination
Csdwheels
一套基于原生JavaScript开发的插件,无依赖、体积小
Stars: ✭ 114 (-30.91%)
Mutual labels:  pagination
Imagelistview
A .NET listview control for image files with asynchronously loaded thumbnails.
Stars: ✭ 113 (-31.52%)
Mutual labels:  listview
Easyadapter
Android 轻量级适配器,简化使用,适应所有的AbsListView、RecyclerView。支持HeaderView与FooterView~
Stars: ✭ 160 (-3.03%)
Mutual labels:  listview
Vuejs Datatable
A Vue.js component for filterable and paginated tables.
Stars: ✭ 148 (-10.3%)
Mutual labels:  pagination
Bootstrap Table
An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation, Vue.js)
Stars: ✭ 11,068 (+6607.88%)
Mutual labels:  pagination
Swipemenulayout
🔥一个零耦合的侧滑菜单,支持RecyclerView、ListView、GridView等不同条目布局,支持菜单在左或在右,可选滑动阻塞,是否禁用等功能
Stars: ✭ 120 (-27.27%)
Mutual labels:  listview
Popularmovies
🎥 Movie discovery app showcasing Android best practices with Google's recommended architecture: MVVM + Repository + Offline support + Android Architecture Components + Paging library & Retrofit2.
Stars: ✭ 142 (-13.94%)
Mutual labels:  pagination
Hibiscus.js
Native Angular directives for Bootstrap4
Stars: ✭ 115 (-30.3%)
Mutual labels:  pagination
Infinitescrolling
Add infinite scrolling to collection view.
Stars: ✭ 156 (-5.45%)
Mutual labels:  pagination
Seven
Eleventy template using Bootstrap, Sass, Webpack, Vue.js powered search, includes lots of other features
Stars: ✭ 114 (-30.91%)
Mutual labels:  pagination
Kotlin Adapter
🔥 RecyclerView,AbsListView适配器, 支持多种视图样式, 支持吸顶、侧滑删除、拖拽效果
Stars: ✭ 132 (-20%)
Mutual labels:  listview
Vue Pagination 2
Vue.js 2 pagination component
Stars: ✭ 144 (-12.73%)
Mutual labels:  pagination
List.js
The perfect library for adding search, sort, filters and flexibility to tables, lists and various HTML elements. Built to be invisible and work on existing HTML.
Stars: ✭ 10,650 (+6354.55%)
Mutual labels:  pagination
Ember Impagination
An Ember Addon that puts the fun back in asynchronous, paginated datasets
Stars: ✭ 123 (-25.45%)
Mutual labels:  pagination

AdvancedList

Swift 5.3 Platforms Current version Build status Code coverage License

This package provides a wrapper view around the SwiftUI List view which adds pagination (through my ListPagination package) and an empty, error 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 ...")
})

📄 Pagination

The Pagination functionality is now (>= 5.0.0) implemented as a modifier. It has three different states: error, idle 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.0, *) {
            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 AdvancedList-SwiftUI.

Migration

Migration 2.x -> 3.0

The AdvancedList was dramatically simplified and is now more like the List and ForEach SwiftUI views.

  1. Delete your list service instances and directly pass your data to the list initializer
  2. Create your views through a content block (initializer parameter) instead of conforming your items to View directly (removed type erased wrapper AnyListItem)
  3. Pass a list state binding to the initializer (before: the ListService managed the list state)
  4. Move and delete: Instead of setting AdvancedListActions on your list service just pass a onMoveAction and/or onDeleteAction block to the initializer

Before:

import AdvancedList

let listService = ListService()
listService.supportedListActions = .moveAndDelete(onMove: { (indexSet, index) in
    // please move me
}, onDelete: { indexSet in
    // please delete me
})
listService.listState = .loading

AdvancedList(listService: listService, emptyStateView: {
    Text("No data")
}, errorStateView: { error in
    VStack {
        Text(error.localizedDescription)
            .lineLimit(nil)
        
        Button(action: {
            // do something
        }) {
            Text("Retry")
        }
    }
}, loadingStateView: {
    Text("Loading ...")
}, pagination: .noPagination)

listService.listState = .loading
// fetch your items ...
listService.appendItems(yourItems)
listService.listState = .items

After:

import AdvancedList

@State private var listState: ListState = .items

AdvancedList(yourData, content: { item in
    Text("Item")
}, listState: $listState, onMoveAction: { (indexSet, index) in
    // move me
}, onDeleteAction: { indexSet in
    // delete me
}, emptyStateView: {
    Text("No data")
}, errorStateView: { error in
    VStack {
        Text(error.localizedDescription)
            .lineLimit(nil)
        
        Button(action: {
            // do something
        }) {
            Text("Retry")
        }
    }
}, loadingStateView: {
    Text("Loading ...")
}, pagination: .noPagination)
Migration 3.0 -> 4.0

Thanks to a hint from @SpectralDragon I could refactor the onMove and onDelete functionality to view modifiers.

Before:

import AdvancedList

@State private var listState: ListState = .items

AdvancedList(yourData, content: { item in
    Text("Item")
}, listState: $listState, onMoveAction: { (indexSet, index) in
    // move me
}, onDeleteAction: { indexSet in
    // delete me
}, emptyStateView: {
    Text("No data")
}, errorStateView: { error in
    VStack {
        Text(error.localizedDescription)
            .lineLimit(nil)
        
        Button(action: {
            // do something
        }) {
            Text("Retry")
        }
    }
}, loadingStateView: {
    Text("Loading ...")
}, pagination: .noPagination)

After:

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 ...")
}, pagination: .noPagination)
.onMove { (indexSet, index) in
    // move me
}
.onDelete { indexSet in
    // delete me
}
Migration 4.0 -> 5.0

Pagination is now implemented as a modifier 💪 And last but not least the code documentation arrived 😀

Before:

private lazy var pagination: AdvancedListPagination<AnyView, AnyView> = {
    .thresholdItemPagination(errorView: { error in
        AnyView(
            VStack {
                Text(error.localizedDescription)
                    .lineLimit(nil)
                    .multilineTextAlignment(.center)

                Button(action: {
                    // load current page again
                }) {
                    Text("Retry")
                }.padding()
            }
        )
    }, loadingView: {
        AnyView(
            VStack {
                Divider()
                Text("Loading...")
            }
        )
    }, offset: 25, shouldLoadNextPage: {
        // load next page
    }, state: .idle)
}()

@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 ...")
}, pagination: pagination)

After:

@State private var listState: ListState = .items
@State private var paginationState: AdvancedListPaginationState = .idle

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 ...")
})
.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.0, *) {
            ProgressView()
        } else {
            Text("Loading ...")
        }
    case let .error(error):
        Text(error.localizedDescription)
    }
})
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].