All Projects → TatsuUkraine → Flutter_sticky_infinite_list

TatsuUkraine / Flutter_sticky_infinite_list

Licence: bsd-2-clause
Multi directional infinite list with Sticky headers for Flutter applications

Programming Languages

dart
5743 projects

Projects that are alternatives of or similar to Flutter sticky infinite list

react-cool-virtual
😎 ♻️ A tiny React hook for rendering large datasets like a breeze.
Stars: ✭ 1,031 (+445.5%)
Mutual labels:  infinite-scroll, sticky-headers
flutter sticky and expandable list
粘性头部与分组列表Sliver实现 Build a grouped list, which support expand/collapse section and sticky headers, support use it with sliver widget.
Stars: ✭ 116 (-38.62%)
Mutual labels:  sticky, sticky-headers
Android-sticky-navigation-layout
android sticky navigation layout
Stars: ✭ 17 (-91.01%)
Mutual labels:  sticky, sticky-headers
Ng Sticky
Angular 4 sticky, have header or any component sticky easy to use.
Stars: ✭ 25 (-86.77%)
Mutual labels:  sticky, sticky-headers
Floatthead
Fixed <thead>. Doesn't need any custom css/html. Does what position:sticky can't
Stars: ✭ 1,193 (+531.22%)
Mutual labels:  sticky, sticky-headers
Consecutivescroller
ConsecutiveScrollerLayout是Android下支持多个滑动布局(RecyclerView、WebView、ScrollView等)和普通控件(TextView、ImageView、LinearLayou、自定义View等)持续连贯滑动的容器,它使所有的子View像一个整体一样连续顺畅滑动。并且支持布局吸顶功能。
Stars: ✭ 1,383 (+631.75%)
Mutual labels:  sticky, sticky-headers
Ngx Scrollspy
Angular ScrollSpy Service
Stars: ✭ 94 (-50.26%)
Mutual labels:  infinite-scroll, sticky
React Virtualized Sticky Tree
A React component for efficiently rendering tree like structures with support for position: sticky
Stars: ✭ 115 (-39.15%)
Mutual labels:  sticky, sticky-headers
Omegarecyclerview
Custom RecyclerView with additional functionality. Allow you add divider, itemSpace, emptyView, sticky header and some other features
Stars: ✭ 132 (-30.16%)
Mutual labels:  sticky-headers
Mypaint
MyPaint is a simple drawing and painting program that works well with Wacom-style graphics tablets.
Stars: ✭ 2,072 (+996.3%)
Mutual labels:  infinite-scroll
React Responsive Carousel
React.js Responsive Carousel (with Swipe)
Stars: ✭ 1,962 (+938.1%)
Mutual labels:  infinite-scroll
Od Virtualscroll
🚀 Observable-based virtual scroll implementation in Angular
Stars: ✭ 133 (-29.63%)
Mutual labels:  infinite-scroll
Infinitescrolling
Add infinite scrolling to collection view.
Stars: ✭ 156 (-17.46%)
Mutual labels:  infinite-scroll
React Simple Infinite Scroll
A brutally simple react infinite scroll component
Stars: ✭ 132 (-30.16%)
Mutual labels:  infinite-scroll
Angular Search Experience
Algolia + Angular = 🔥🔥🔥
Stars: ✭ 167 (-11.64%)
Mutual labels:  infinite-scroll
Vue Quick Loadmore
A pull-down refresh and pull-up infinite scroll component for Vue.js.--vue移动端下拉刷新上拉无限滚动加载插件,支持更换加载图片,保存和设置滚动距离等。
Stars: ✭ 129 (-31.75%)
Mutual labels:  infinite-scroll
React Native Keyboard Accessory View
Keyboard accessory (sticky) view for your React Native app. Supports interactive dismiss on iOS.
Stars: ✭ 128 (-32.28%)
Mutual labels:  sticky
Flutter smart select
SmartSelect allows you to easily convert your usual form select or dropdown into dynamic page, popup dialog, or sliding bottom sheet with various choices input such as radio, checkbox, switch, chips, or even custom input. Supports single and multiple choice.
Stars: ✭ 179 (-5.29%)
Mutual labels:  sticky-headers
Stickyfloat
This plugin makes it possible to have a fixed position element that is relative to it’s parent. A normal fixed positioned element would be “out of context” and is very difficult to use in the most common situations with fluid designs. This plugin solves that problem with as little code as I could possible get it so it will run in the most optimized way, while also allow you to customize it in many important ways which might suit you best.
Stars: ✭ 166 (-12.17%)
Mutual labels:  sticky
Fairygui Unity
A flexible UI framework for Unity
Stars: ✭ 2,007 (+961.9%)
Mutual labels:  infinite-scroll

Sticky Infinite List

pub package Awesome Flutter

Infinite list with sticky headers.

This package was made in order to make possible render infinite list in both directions with sticky headers, unlike most packages in Dart Pub.

Supports various header positioning. Also supports Vertical and Horizontal scroll list

It highly customizable and doesn't have any third party dependencies or native(Android/iOS) code.

In addition to default usage, this package exposes some classes, that can be overridden if needed. Also some classes it can be used inside Scrollable widgets independently from InfiniteList container.

This package uses CustomScrollView to perform scroll with all benefits for performance that Flutter provides.

Features

  • sticky headers within infinite list
  • multi directional infinite list
  • customization for sticky header position
  • horizontal sticky list support
  • dynamic header build on content scroll
  • dynamic min offset calculation on content scroll

Flutter before 1.20

If you're using Flutter version lower than 1.20 consider using v2.x.x.

Migration guide

If you using older MAJOR versions, please visit this migration guide

Property not defined

If you get similar error message during the build please read this section first.

Demo

Getting Started

Install package and import

import 'package:sticky_infinite_list/sticky_infinite_list.dart';

Package exposes InfiniteList, InfiniteListItem, StickyListItem, StickyListItemRenderObject classes

Examples

Simple example

To start using Infinite list with sticky headers, you need to create instance InfiniteList with builder specified.

No need to specify any additional config to make it work

import 'package:sticky_infinite_list/sticky_infinite_list.dart';

class Example extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return InfiniteList(
      builder: (BuildContext context, int index) {
        /// Builder requires [InfiniteList] to be returned
        return InfiniteListItem(
          /// Header builder
          headerBuilder: (BuildContext context) {
            return Container(
              ///...
            );
          },
          /// Content builder
          contentBuilder: (BuildContext context) {
            return Container(
              ///...
            );
          },
        );
      }
    );
  }
}

Or with header overlay content

import 'package:sticky_infinite_list/sticky_infinite_list.dart';

class Example extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return InfiniteList(
      builder: (BuildContext context, int index) {
        /// Builder requires [InfiniteList] to be returned
        return InfiniteListItem.overlay(
          /// Header builder
          headerBuilder: (BuildContext context) {
            return Container(
              ///...
            );
          },
          /// Content builder
          contentBuilder: (BuildContext context) {
            return Container(
              ///...
            );
          },
        );
      }
    );
  }
}

State

When min offset callback invoked or header builder is invoked object StickyState is passed as parameter

This object describes current state for sticky header.

class StickyState<I> {
  /// Position, that header already passed
  ///
  /// Value can be between 0.0 and 1.0
  ///
  /// If it's `0.0` - sticky in max start position
  ///
  /// `1.0` - max end position
  ///
  /// If [InfiniteListItem.initialHeaderBuild] is true, initial
  /// header render will be with position = 0
  final double position;

  /// Number of pixels, that outside of viewport
  ///
  /// If [InfiniteListItem.initialHeaderBuild] is true, initial
  /// header render will be with offset = 0
  /// 
  /// For header bottom positions (or right positions for horizontal)
  /// offset value also will be amount of pixels that was scrolled away
  final double offset;

  /// Item index
  final I index;

  /// If header is in sticky state
  ///
  /// If [InfiniteListItem.minOffsetProvider] is defined,
  /// it could be that header builder will be emitted with new state
  /// on scroll, but [sticky] will be false, if offset already passed
  /// min offset value
  ///
  /// WHen [InfiniteListItem.minOffsetProvider] is called, [sticky]
  /// will always be `false`. Since for min offset calculation
  /// offset itself not defined yet
  final bool sticky;

  /// Scroll item height.
  ///
  /// If [InfiniteListItem.initialHeaderBuild] is true, initial
  /// header render will be called without this value
  final double contentSize;
}

Extended configuration

Available configuration

Alongside with minimal config to start using.

InfiniteList allows you to define config for scroll list rendering

InfiniteList(
  /// Optional parameter to pass ScrollController instance
  controller: ScrollController(),
  
  /// Optional parameter
  /// to specify scroll direction
  /// 
  /// By default scroll will be rendered with just positive
  /// direction `InfiniteListDirection.forward`
  /// 
  /// If you need infinite list in both directions use `InfiniteListDirection.multi`
  direction: InfiniteListDirection.multi,
  
  /// Negative max child count.
  /// 
  /// Will be used only when `direction: InfiniteListDirection.multi`
  /// 
  /// If it's not provided, scroll will be infinite in negative direction
  negChildCount: 100,
  
  /// Positive max child count
  /// 
  /// Specifies number of elements for forward list
  /// 
  /// If it's not provided, scroll will be infinite in positive direction
  posChildCount: 100,
  
  /// ScrollView anchor value.
  anchor: 0.0,
  
  /// ScrollView physics value.
  physics: null,

  /// Item builder
  /// 
  /// Should return `InfiniteListItem`
  builder: (BuildContext context, int index) {
    return InfiniteListItem(
      //...
    )
  }
)

InfiniteListItem allows you to specify more options for you customization.

InfiniteListItem(
  /// See class description for more info
  /// 
  /// Forces initial header render when [headerStateBuilder]
  /// is specified.
  initialHeaderBuild: false,

  /// Simple Header builder
  /// that will be called once during List item render
  headerBuilder: (BuildContext context) {},
  
  /// Header builder, that will be invoked each time
  /// when header should change it's position
  /// 
  /// Unlike prev method, it also provides `state` of header
  /// position
  /// 
  /// This callback has higher priority than [headerBuilder],
  /// so if both header builders will be provided,
  /// [headerBuilder] will be ignored
  headerStateBuilder: (BuildContext context, StickyState<int> state) {},
  
  /// Content builder
  contentBuilder: (BuildContext context) {},
  
  /// Min offset invoker
  /// 
  /// This callback is called on each header position change,
  /// to define when header should be stick to the bottom of
  /// content.
  /// 
  /// If this method returns `0`,
  /// header will be in sticky state until list item
  /// will be visible inside view port
  /// 
  /// If this method not provided or it returns null, header
  /// will be sticky until offset equals to 
  /// header size
  minOffsetProvider: (StickyState<int> state) {},
  
  /// Header alignment against main axis direction
  ///
  /// See [HeaderMainAxisAlignment] for more info
  HeaderMainAxisAlignment mainAxisAlignment: HeaderMainAxisAlignment.start,

  /// Header alignment against cross axis direction
  ///
  /// See [HeaderCrossAxisAlignment] for more info
  HeaderCrossAxisAlignment crossAxisAlignment: HeaderCrossAxisAlignment.start,

  /// Header position against scroll axis for relative positioned headers
  ///
  /// Only for relative header positioning
  HeaderPositionAxis positionAxis: HeaderPositionAxis.mainAxis,

  /// List item padding, see [EdgeInsets] for more info
  EdgeInsets padding: const EdgeInsets.all(8.0),
  
  /// Scroll direction
  ///
  /// Can be vertical or horizontal (see [Axis] class)
  ///
  /// This value also affects how bottom or top
  /// edge header positioned headers behave
  scrollDirection: Axis.vertical,
);

Demos

Header alignment demo

Relative positioning

Relative cross axis positioning

Overlay positioning

Horizontal scroll demo

Reverse infinite scroll

Currently package doesn't support CustomScrollView.reverse option.

But same result can be achieved with defining anchor = 1 and posChildCount = 0. In that way viewport center will be stick to the bottom and positive list won't render anything.

Additionally you can specify header alignment to any side.

import 'package:sticky_infinite_list/sticky_infinite_list.dart';

class Example extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return InfiniteList(
      anchor: 1.0,
      
      direction: InfiniteListDirection.multi,
      
      posChildCount: 0,
      
      builder: (BuildContext context, int index) {
        /// Builder requires [InfiniteList] to be returned
        return InfiniteListItem(
        
          mainAxisAlignment: HeaderMainAxisAlignment.end,
          crossAxisAlignment: HeaderCrossAxisAlignment.start,
          
          /// Header builder
          headerBuilder: (BuildContext context) {
            return Container(
              ///...
            );
          },
          /// Content builder
          contentBuilder: (BuildContext context) {
            return Container(
              ///...
            );
          },
        );
      }
    );
  }
}

Demo

For more info take a look at Example project

Available for override

In most cases it will be enough to just use InfiniteListItem

But in some cases you may need to add additional functionality to each item.

Luckily you can extend and override base InfiniteListItem class

/// Generic `I` is index type, by default list item uses `int`

class SomeCustomListItem<I> extends InfiniteListItem<I> {
  /// Header alignment against main axis direction
  ///
  /// See [HeaderMainAxisAlignment] for more info
  @override
  final HeaderMainAxisAlignment mainAxisAlignment = HeaderMainAxisAlignment.start;

  /// Header alignment against cross axis direction
  ///
  /// See [HeaderCrossAxisAlignment] for more info
  @override
  final HeaderCrossAxisAlignment crossAxisAlignment = HeaderCrossAxisAlignment.start;

  /// Header position against scroll axis for relative positioned headers
  ///
  /// See [HeaderPositionAxis] for more info
  @override
  final HeaderPositionAxis positionAxis = HeaderPositionAxis.mainAxis;

  /// If header should overlay content or not
  @override
  final bool overlayContent = false;

  /// Let item builder know if it should watch
  /// header position changes
  /// 
  /// If this value is `true` - it will invoke [buildHeader]
  /// each time header position changes
  @override
  bool get watchStickyState => true;

  /// Let item builder know that this class
  /// provides header
  /// 
  /// If it returns `false` - [buildHeader] will be ignored 
  /// and never called
  @override
  bool get hasStickyHeader => true;

  /// This methods builds header
  /// 
  /// If [watchStickyState] is `true`,
  /// it will be invoked on each header position change
  /// and `state` option will be provided
  /// 
  /// Otherwise it will be called only once on initial render
  /// and each header position change won't invoke this method.
  /// 
  /// Also in that case `state` will be `null`
  @override
  Widget buildHeader(BuildContext context, [StickyState<I> state]) {}

  /// Content item builder
  /// 
  /// This method invoked only once
  @override
  Widget buildContent(BuildContext context) {}

  /// Called during init state (see [Statefull] widget [State.initState])
  /// 
  /// For additional information about [Statefull] widget `initState`
  /// lifecycle - see Flutter docs
  @protected
  @mustCallSuper
  void initState() {}

  /// Called during item dispose (see [Statefull] widget [State.dispose])
  /// 
  /// For additional information about [Statefull] widget `dispose`
  /// lifecycle - see Flutter docs
  @protected
  @mustCallSuper
  void dispose() {}
}

Need more override?..

Alongside with list item override, to use inside InfiniteList builder, you can also use or extend StickyListItem, that exposed by this package too, independently.

This class uses Stream to inform it's parent about header position changes

Also it requires to be rendered inside Scrollable widget and Viewport, since it subscribes to scroll event and calculates position against Viewport coordinates (see StickyListItemRenderObject class for more information)

For example

Widget build(BuildContext context) {
  return SingleChildScrollView(
    child: Column(
      children: <Widget>[
        Container(
          height: height,
          color: Colors.lightBlueAccent,
          child: Placeholder(),
        ),
        StickyListItem<String>(
          streamSink: _headerStream.sink, /// stream to update header during scroll
          header: Container(
            height: _headerHeight,
            width: double.infinity,
            color: Colors.orange,
            child: Center(
              child: StreamBuilder<StickyState<String>>(
                stream: _headerStream.stream, /// stream to update header during scroll
                builder: (_, snapshot) {
                  if (!snapshot.hasData) {
                    return Container();
                  }

                  final position = (snapshot.data.position * 100).round();

                  return Text('Positioned relative. Position: $position%');
                },
              ),
            ),
          ),
          content: Container(
            height: height,
            color: Colors.blueAccent,
            child: Placeholder(),
          ),
          itemIndex: "single-child",
        ),
        StickyListItem<String>.overlay(
          streamSink: _headerOverlayStream.sink, /// stream to update header during scroll
          header: Container(
            height: _headerHeight,
            width: double.infinity,
            color: Colors.orange,
            child: Center(
              child: StreamBuilder<StickyState<String>>(
                stream: _headerOverlayStream.stream, /// stream to update header during scroll
                builder: (_, snapshot) {
                  if (!snapshot.hasData) {
                    return Container();
                  }

                  final position = (snapshot.data.position * 100).round();

                  return Text('Positioned overlay. Position: $position%');
                },
              ),
            ),
          ),
          content: Container(
            height: height,
            color: Colors.lightBlueAccent,
            child: Placeholder(),
          ),
          itemIndex: "single-overlayed-child",
        ),
        Container(
          height: height,
          color: Colors.cyan,
          child: Placeholder(),
        ),
      ],
    ),
  );
}

This code will render single child scroll with 4 widgets. Two middle items - items with sticky header.

Demo

For more complex example please take a look at "Single Example" page in Example project

Changelog

Please see the Changelog page to know what's recently changed.

Bugs/Requests

If you encounter any problems feel free to open an issue. If you feel the library is missing a feature, please raise a ticket on Github and I'll look into it. Pull request are also welcome.

Known issues

Currently this package can't work with reverse scroll. For some reason flutter calculates coordinate for negative list items in a different way in reverse mode, comparing to regular scroll direction.

But there is an workaround can be used, described in Reverse infinite scroll

Flutter version related errors

Named parameter clipBehavior isn't defined error

If you get this kind of error, most likely you are using Flutter 1.17. If so, please ensure that you're using 2.x.x version.

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].