All Projects → deakjahn → huge_listview

deakjahn / huge_listview

Licence: MIT License
A performant list with any number of items.

Programming Languages

dart
5743 projects

Projects that are alternatives of or similar to huge listview

ClassifySimpleDemo
二级列表,商品分类,RecyclerView,expanablelistview
Stars: ✭ 48 (+128.57%)
Mutual labels:  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 (+33.33%)
Mutual labels:  listview
react-native-wxui
A UI package for React Native
Stars: ✭ 21 (+0%)
Mutual labels:  listview
AdvancedList-SwiftUI
MOVED to https://github.com/crelies/AdvancedList | Advanced list with empty, error and loading state implemented with SwiftUI
Stars: ✭ 41 (+95.24%)
Mutual labels:  listview
sectionedmergeadapter
Work with sub-sections in your Android ListView
Stars: ✭ 22 (+4.76%)
Mutual labels:  listview
imgui
Dear ImGui Addons Branch = plain unmodified dear imgui plus some extra addon.
Stars: ✭ 348 (+1557.14%)
Mutual labels:  listview
treelistview
A Pascal treelistview component, showing a treeview together with the columns of a listview (for Delphi and Lazarus)
Stars: ✭ 41 (+95.24%)
Mutual labels:  listview
react-native-masonry-brick-list
Staggered Or Masonary List View For React Native Written in pure js
Stars: ✭ 24 (+14.29%)
Mutual labels:  listview
FlutterNote
Easy to learn Flutter(Flutter 即学即用,Flutter 速成必备)
Stars: ✭ 22 (+4.76%)
Mutual labels:  listview
GenericAdapter
⛳️ Easy to use android databinding ready recyclerview adapter
Stars: ✭ 26 (+23.81%)
Mutual labels:  listview
ListViewWithSubListView
Xamarin.Forms Expandable ListView With Sub-ListView MVVM Pattern
Stars: ✭ 40 (+90.48%)
Mutual labels:  listview
TwerkyListView
A beautifully animated recycler-list-view, that twerks the way African earthworms do in order to move
Stars: ✭ 19 (-9.52%)
Mutual labels:  listview
LimitlessUI
Awesome C# UI library that highly reduced limits of your application looks
Stars: ✭ 41 (+95.24%)
Mutual labels:  listview
user profile
User profile UI designed in flutter
Stars: ✭ 14 (-33.33%)
Mutual labels:  listview
react-native-nested-listview
A UI component for React Native for representing nested arrays of N levels
Stars: ✭ 163 (+676.19%)
Mutual labels:  listview
LoginAndRegistrationWithSocialMedia
Created a Project to design login screen, registration screen, login with google ,slider navigation drawer,dashboard screen login with Facebook using Flutter
Stars: ✭ 82 (+290.48%)
Mutual labels:  listview
react-native-card-list
A React Native component which displays a list of image cards that zoom to fullscreen
Stars: ✭ 19 (-9.52%)
Mutual labels:  listview
cgridlistctrlex
MFC Grid control using a custom draw CListCtrl with subitem editing and formatting
Stars: ✭ 80 (+280.95%)
Mutual labels:  listview
android-page
android 分页列表数据加载引擎,主要封装了android分页列表数据加载的各个组件,如果你有一个需要分页加载的List列表,都可以使用此框架实现。
Stars: ✭ 15 (-28.57%)
Mutual labels:  listview
react-native-paginated-listview
A simple paginated react-native ListView with a few customization options
Stars: ✭ 14 (-33.33%)
Mutual labels:  listview

Huge ListView

A performant ListView that can handle any number of items with ease. Unlike other infinite list approaches, it doesn't just add new items to the list, growing to huge sizes in the end, but has a fixed size cache that only keeps a handful of pages all the time, discarding old pages as new ones come in. The list asks for a pageful of items at once, in an async function, expecting to receive a Future<List<T>> of your items.

Instead of a regular ListView, it uses a ScrollablePositionedList inside that makes it possible to scroll to specific items rather than scroll positions. The items don't have to be of uniform height, their size differences don't affect performance at all. This list implementation, however, doesn't play nice with the regular Scrollbar, so we use our own DraggableScrollbar instead. This way we can support both a scrollbar and the usual position-based scrolling as well.

The basic idea came from:

The scrollbar is based on:

Usage

static const int PAGE_SIZE = 12;
final listKey = GlobalKey<HugeListViewState>();
final scroll = ItemScrollController();

HugeListView<MyDataItem>(
  /// Only needed if you expect to make use of its [setPosition] function.
  key: listKey,
  /// Only needed if you expect to make use of its [jumpTo] or [scrollTo] functions.
  controller: scroll,
  /// Size of the page. [HugeListView] only keeps a few pages of items in memory any time.
  pageSize: PAGE_SIZE,
  /// Total number of items in the list.
  totalCount: 999999,
  /// Index of an item to initially align within the viewport.
  startIndex: 0,
  /// Called to build items for the list with the specified [pageIndex].
  pageFuture: (page) => _loadPage(page, PAGE_SIZE),
  /// Called to build an individual item with the specified [index].
  itemBuilder: (context, index, MyDataItem entry) {
    return Text(entry.name);
  },
  /// Called to build the thumb. One of [DraggableScrollbarThumbs.RoundedRectThumb], [DraggableScrollbarThumbs.ArrowThumb],
  /// [DraggableScrollbarThumbs.SemicircleThumb] or build your own.
  thumbBuilder: DraggableScrollbarThumbs.SemicircleThumb,
  /// Background color of scroll thumb, defaults to white.
  thumbBackgroundColor: Colors.white,
  /// Drawing color of scroll thumb, defaults to gray.
  thumbDrawColor: Colors.grey,
  /// Height of scroll thumb, defaults to 48.
  thumbHeight: 48,
  /// Called to build a placeholder while the item is not yet availabe.
  placeholderBuilder: (context, index) => <some Widget>,
  /// Called to build a progress widget while the whole list is initialized.
  waitBuilder: (context) => <some Widget>,
  /// Called to build a widget when the list is empty.
  emptyResultBuilder: (context) => <some Widget>,
  /// Called to build a widget when there is an error.
  errorBuilder: (context, error) => <some Widget>,
  /// Event to call with the index of the topmost visible item in the viewport while scrolling.
  /// Can be used eg. to display the current letter of an alphabetically sorted list.
  firstShown: (index) {},
  /// The axis along which the list view scrolls. Defaults to [Axis.vertical].
  scrollDirection: Axis.vertical,
  /// The amount of space by which to inset the list.
  padding: EdgeInsets.all(6.0),
);

You have to pass a list of your items to pageFuture, for instance, given a list named data:

Future<List<MyDataItem>> _loadPage(int page, int pageSize) async {
  int from = page * pageSize;
  int to = min(data.length, from + pageSize);
  return data.sublist(from, to);
}

The waitBuilder can be a simple centered CircularProgressIndicator but a nicer idea is to provide a placeholderBuilder that is a mockup of the data to arrive. Many apps and sites use gray horizontal bars instead of the actual text during loading. As an example, here is a simple function that creates such a bar with randomly varying length:

static const int PLACEHOLDER_SIZE = 14;

Widget buildPlaceholder() {
  double margin = Random().nextDouble() * 50;
  return Padding(
    padding: EdgeInsets.fromLTRB(3, 3, 3 + margin, 3),
    child: Container(
      height: PLACEHOLDER_SIZE,
      color: Colors.grey,
    ),
  );
}

You can pass it directly to placeholderBuilder and you can also use it to create a whole page of text mockup bars that you can pass to waitBuilder:

Widget buildWait() {
  return LayoutBuilder(
    builder: (_, constraints) {
      return ListView.builder(
        itemCount: (constraints.maxHeight / PLACEHOLDER_SIZE).ceil(),
        itemBuilder: (_, index) => buildPlaceholder(),
      );
    },
  );
}

Custom thumb

In order to use a custom thumb, provide a builder:

thumbBuilder: (Color backgroundColor, Color drawColor, double height, int index) {
  return ScrollBarThumb(backgroundColor, drawColor, height, index.toString());
}

where ScrollBarThumb can be:

class ScrollBarThumb extends StatelessWidget {
  final backgroundColor;
  final drawColor;
  final height;
  final title;

  const ScrollBarThumb(
    this.backgroundColor,
    this.drawColor,
    this.height,
    this.title, {
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Container(
          padding: EdgeInsets.all(8),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(10),
            color: Colors.white.withOpacity(0.8),
          ),
          child: Text(
            title,
            style: TextStyle(
              color: Colors.black,
              backgroundColor: Colors.transparent,
              fontSize: 14,
            ),
          ),
        ),
        Padding(
          padding: EdgeInsets.all(2),
        ),
        CustomPaint(
          foregroundPainter: _ArrowCustomPainter(drawColor),
          child: Material(
            elevation: 4.0,
            child: Container(constraints: BoxConstraints.tight(Size(height * 0.6, height))),
            color: backgroundColor,
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(height),
              bottomLeft: Radius.circular(height),
              topRight: Radius.circular(4.0),
              bottomRight: Radius.circular(4.0),
            ),
          ),
        ),
      ],
    );
  }
}

class _ArrowCustomPainter extends CustomPainter {
  final Color drawColor;

  _ArrowCustomPainter(this.drawColor);

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill
      ..color = drawColor;
    const width = 12.0;
    const height = 8.0;
    final baseX = size.width / 2;
    final baseY = size.height / 2;

    canvas.drawPath(trianglePath(Offset(baseX - 4.0, baseY - 2.0), width, height, true), paint);
    canvas.drawPath(trianglePath(Offset(baseX - 4.0, baseY + 2.0), width, height, false), paint);
  }

  static Path trianglePath(Offset offset, double width, double height, bool isUp) {
    return Path()
      ..moveTo(offset.dx, offset.dy)
      ..lineTo(offset.dx + width, offset.dy)
      ..lineTo(offset.dx + (width / 2),
          isUp ? offset.dy - height : offset.dy + height)
      ..close();
  }
}
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].