GithubHelp home page GithubHelp logo

fluttercommunity / flutter_sticky_headers Goto Github PK

View Code? Open in Web Editor NEW
1.1K 1.1K 129.0 24.23 MB

Flutter Sticky Headers - Lets you place "sticky headers" into any scrollable content in your Flutter app. No special wrappers or magic required. Maintainer: @slightfoot

Home Page: https://pub.dev/packages/sticky_headers

License: MIT License

Objective-C 0.08% Dart 98.75% Kotlin 0.27% Swift 0.89%

flutter_sticky_headers's Introduction

Flutter Community

Flutter Community

A central place for community made Flutter content.


The Flutter Community is an organization aimed at providing a central place for community made Flutter packages and content to live.

Our goal is to ensure packages made by the Flutter community are kept alive and maintained in one place.

Medium Articles

To go along with the packages, we have started a Medium publication as a central location for community content to be published - especially if it relates to the packages here.

https://medium.com/flutter-community

Packages

These are the packages featured on the Flutter Community.

Name Release Description Maintainer
android_alarm_manager_plus Pub Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire. Miguel Beltran
android_id Pub Flutter plugin for retrieving the Android ID. Not supported on iOS. Joachim Nohl
android_intent_plus Pub Flutter plugin for launching Android Intents. Not supported on iOS. Miguel Beltran
app_review Pub Request and Write Reviews and Open Store Listing for Android and iOS in Flutter. Rody Davis
backdrop Pub Backdrop implementation in dart. (https://material.io/design/components/backdrop.html) Harsh Bhikadia
breakpoint Pub A Flutter plugin to calculate the material design breakpoints. Rody Davis
sealed_unions Pub Sealed Unions for Dart George Medve
firestore_helpers Pub Firestore helper function to create dynamic and location based queries Thomas Burkhart
draggable_scrollbar Pub A scrollbar that can be dragged for quickly navigation through a vertical list. Additional option is showing label next to scrollthumb with information about current item. Marina Kuznetsova
after_layout Pub Execute code after the first layout of your widget has been performed, i.e. after the first frame has been displayed. Simon Lightfoot
flutter_blurhash Pub Compact representation of a placeholder for an image. Encode a blurry image under 30 caracters for instant display like used by Medium Robert Felker
contacts_service Pub A Flutter plugin to retrieve and manage contacts on Android and iOS devices. Lukas Dickie
flutter_downloader Pub A plugin for creating and managing download tasks. Supports iOS and Android. Hung Duy Ha
flutter_google_places Pub Google places autocomplete widgets for flutter. No wrapper, use https://pub.dartlang.org/packages/google_maps_webservice Kev Morelli
infinite_listview Pub ListView with items that can be scrolled infinitely in both directions. Simon Lightfoot
flutter_launcher_icons Pub A package which simplifies the task of updating your Flutter app's launcher icon. Mark O'Sullivan
flutter_sms Pub A Flutter plugin to Send SMS and MMS on iOS and Android. If iMessage is enabled it will send as iMessage on iOS. This plugin must be tested on a real device on iOS. Rody Davis
sticky_headers Pub Flutter Sticky Headers - Lets you place headers on scrollable content that will stick to the top of the container whilst the content is scrolled. Simon Lightfoot
flutter_uploader Pub A plugin for creating and managing upload tasks with optional background exection support. Sebastian Roth
wear Pub A plugin that offers Flutter support for Wear OS by Google NO MAINTAINER PROVIDED
flutter_webview_plugin Pub Plugin that allow Flutter to communicate with a native Webview. Rafal Wachol
flutter_whatsnew Pub A new Flutter package to show updates to users. Rody Davis
workmanager Pub Flutter Workmanager. This plugin allows you to schedule background work on Android and iOS. NO MAINTAINER PROVIDED
font_awesome_flutter Pub The Font Awesome Icon pack available as Flutter Icons. Provides 1500 additional icons to use in your apps. Brian Egan
get_it Pub Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App" Thomas Burkhart
get_version Pub Get the Version Name, Version Code, Platform and OS Version, and App ID on iOS and Android. Rody Davis
import_sorter Pub Automatically sort all your dart imports. Support for any dart project. Matthew Gleich
native_widgets Pub A new Flutter package for using Android and iOS natively on each platform. Rody Davis
page_turn Pub Page Turn Widget - Add a page turn effect to widgets in your app. Rody Davis
persist_theme Pub A flutter plugin for persisting the theme data. Support for Dark Mode. Rody Davis
redux Pub Redux is a predictable state container for Dart and Flutter apps John Ryan
redux_undo Pub Make your redux store undo- and redoable. Inspired by the JS redux_undo package. Michel Engelen
responsive_scaffold Pub On mobile it shows a list and pushes to details and on tablet it shows the List and the selected item. Rody Davis
rx_command Pub Reactive event handler wrapper class inspired by ReactiveUI. Thomas Burkhart
state_persistence Pub Persist state across app launches. By default this library store state as a local JSON file called data.json in the applications data directory. Simon Lightfoot

Submitting your packages

If you'd like to submit your package to the Flutter Community GitHub organization, please see the Flutter Community Transfer Guide.

Getting in contact

For any questions regarding the Flutter Community, please open an issue on the /community repository.

Note to packages owners

Flutter Community aims to bring the best community-made packages forward. Because of this, not all proposed packages will be accepted.

flutter_sticky_headers's People

Contributors

amir-dragon avatar jeroen-meijer avatar slightfoot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter_sticky_headers's Issues

Content distributed over several headers

Given a list of items, ['Ambrose', 'Brian', 'Bradford', 'Chester', 'Cardiff', 'Cooper', 'David', 'Done', 'Doomed', 'Darby', 'Exeter', 'Eclipse', 'Endorfin', 'End', 'Elephant'], I expect the following output:

A
Ambrose

B
Brian
Bradford

C
Chester
Cardiff
Cooper

D
David
Done
Doomed
Darby

E
Exeter
Eclipse
Endorfin
End
Elephant


However, I get something different... when the number of items beginning with a specific letter is:

  1. results in 1 header and a single item (as expected)
  2. results in 2 duplicate headers and contents
  3. results in 3 duplicate headers and contents
    ... and so on

For example:

A
Ambrose

B
Brian
Bradford

B
Brian
Bradford

C
Chester
Cardiff
Cooper

C
Chester
Cardiff
Cooper

C
Chester
Cardiff
Cooper


Below is the code to replicate this problem. Am I using the library incorrectly?

import 'package:flutter/material.dart';
import 'package:sticky_headers/sticky_headers/widget.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView.builder(itemBuilder: (context, index) {
          var header = nodes.elementAt(index).substring(0, 1);
          return StickyHeader(
            header: Text(header),
            content: Column(
              children: nodes
                  .where((node) => node.startsWith(header))
                  .map((node) => Text(node))
                  .toList(),
            ),
          );
        }),
      ),
    );
  }
}

var nodes = [
  'Ambrose',
  'Brian',
  'Bradford',
  'Chester',
  'Cardiff',
  'Cooper',
  'David',
  'Done',
  'Doomed',
  'Darby',
  'Exeter',
  'Eclipse',
  'Endorfin',
  'End',
  'Elephant'
];

Error console when I show detail is over display.

package >> https://pub.dev/packages/sticky_headers

I have to use the fix header listview,
but my detail is over display
but even so I have to make use of freezing.

[/] display not problem when I show detail fit display.
image

[X] when I show detail is over display (horizontal)
image

Finally I resolve by add code in ListView widget below,

Add here >>>> scrollDirection: renderer.Axis.horizontal

child: ListView(
                scrollDirection: renderer.Axis.horizontal,
                children: <Widget>[
                  StickyHeader(
                    header: Container(
               .........
               .........

image

Display show detail no problem.


But have Error console Flutter, How to resolve ?

I/flutter (26365): โ•โ•โ•ก EXCEPTION CAUGHT BY RENDERING LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
I/flutter (26365): The following assertion was thrown during performLayout():
I/flutter (26365): RenderStickyHeader does not meet its constraints.
I/flutter (26365): Constraints: BoxConstraints(0.0<=w<=Infinity, h=407.0)
I/flutter (26365): Size: Size(1200.0, 447.0)
I/flutter (26365): If you are not writing your own RenderBox subclass, then this is not your fault. Contact support:
I/flutter (26365): https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter (26365): 
I/flutter (26365): When the exception was thrown, this was the stack:
I/flutter (26365): #0      RenderBox.debugAssertDoesMeetConstraints.<anonymous closure> (package:flutter/src/rendering/box.dart:1764:9)
I/flutter (26365): #1      RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:1823:6)
I/flutter (26365): #2      RenderBox.size=.<anonymous closure> (package:flutter/src/rendering/box.dart:1543:17)
I/flutter (26365): #3      RenderBox.size= (package:flutter/src/rendering/box.dart:1543:65)
I/flutter (26365): #4      RenderStickyHeader.performLayout (package:sticky_headers/sticky_headers/render.dart:110:5)
I/flutter (26365): #5      RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #6      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #7      RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #8      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #9      RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #10     RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:165:27)
I/flutter (26365): #11     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #12     RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:182:11)
I/flutter (26365): #13     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #14     RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:407:13)
I/flutter (26365): #15     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1322:12)
I/flutter (26365): #16     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1240:20)
I/flutter (26365): #17     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #18     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #19     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #20     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #21     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #22     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #23     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #24     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #25     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #26     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #27     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #28     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #29     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #30     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #31     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #32     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #33     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #34     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #35     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #36     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:799:17)
I/flutter (26365): #37     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #38     RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:799:17)
I/flutter (26365): #39     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #40     RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:199:11)
I/flutter (26365): #41     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #42     RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:259:13)
I/flutter (26365): #43     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #44     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:142:11)
I/flutter (26365): #45     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:431:7)
I/flutter (26365): #46     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:212:7)
I/flutter (26365): #47     RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:356:14)
I/flutter (26365): #48     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #49     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #50     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #51     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #52     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1206:11)
I/flutter (26365): #53     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #54     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #55     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #56     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #57     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #58     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #59     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #60     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #61     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #62     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #63     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #64     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #65     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #66     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #67     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #68     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #69     RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3015:13)
I/flutter (26365): #70     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #71     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:510:15)
I/flutter (26365): #72     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #73     __RenderTheatre&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #74     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #75     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #76     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #77     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #78     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #79     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #80     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #81     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #82     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #83     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:105:13)
I/flutter (26365): #84     RenderObject.layout (package:flutter/src/rendering/object.dart:1644:7)
I/flutter (26365): #85     RenderView.performLayout (package:flutter/src/rendering/view.dart:151:13)
I/flutter (26365): #86     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1519:7)
I/flutter (26365): #87     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:766:18)
I/flutter (26365): #88     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:347:19)
I/flutter (26365): #89     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:701:13)
I/flutter (26365): #90     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:286:5)
I/flutter (26365): #91     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1012:15)
I/flutter (26365): #92     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:952:9)
I/flutter (26365): #93     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:773:7)
I/flutter (26365): #95     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:382:19)
I/flutter (26365): #96     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
I/flutter (26365): #97     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:171:12)
I/flutter (26365): (elided one frame from package dart:async-patch)
I/flutter (26365): 
I/flutter (26365): The following RenderObject was being processed when the exception was fired:
I/flutter (26365):   RenderStickyHeader#b1a40 relayoutBoundary=up5 NEEDS-LAYOUT NEEDS-PAINT
I/flutter (26365):   creator: StickyHeader โ† RepaintBoundary-[<0>] โ† IndexedSemantics โ†
I/flutter (26365):   NotificationListener<KeepAliveNotification> โ† KeepAlive โ† AutomaticKeepAlive โ† SliverList โ†
I/flutter (26365):   MediaQuery โ† SliverPadding โ† Viewport โ† IgnorePointer-[GlobalKey#9c11d] โ† Semantics โ† โ‹ฏ
I/flutter (26365):   parentData: <none> (can use size)
I/flutter (26365):   constraints: BoxConstraints(0.0<=w<=Infinity, h=407.0)
I/flutter (26365):   layer: OffsetLayer#517c4
I/flutter (26365):   size: Size(1200.0, 447.0)
I/flutter (26365): This RenderObject had the following descendants (showing up to depth 5):
I/flutter (26365):   RenderRepaintBoundary#cca85 relayoutBoundary=up6 NEEDS-PAINT
I/flutter (26365):     RenderCustomPaint#61625 relayoutBoundary=up7 NEEDS-PAINT
I/flutter (26365):       RenderRepaintBoundary#00c12 relayoutBoundary=up8 NEEDS-PAINT
I/flutter (26365):         _RenderScrollSemantics#069c0 relayoutBoundary=up9 NEEDS-PAINT
I/flutter (26365):           RenderPointerListener#31d18 relayoutBoundary=up10 NEEDS-PAINT
I/flutter (26365):   RenderConstrainedBox#30f49 relayoutBoundary=up6 NEEDS-PAINT
I/flutter (26365):     RenderDecoratedBox#01306 relayoutBoundary=up7 NEEDS-PAINT
I/flutter (26365):       RenderPadding#53801 relayoutBoundary=up8 NEEDS-PAINT
I/flutter (26365):         RenderPositionedBox#7f27c relayoutBoundary=up9 NEEDS-PAINT
I/flutter (26365):           RenderFlex#67324 relayoutBoundary=up10 NEEDS-PAINT
I/flutter (26365): โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

My code

import 'package:flutter/rendering.dart' as renderer;
import 'package:sticky_headers/sticky_headers.dart';

Flexible(
  flex: 55,
  child: ListView(
	scrollDirection: renderer.Axis.horizontal,
	children: <Widget>[
	  StickyHeader(
		header: Container(
		  height: 40.0,
		  color: renderer.Color(0xFFD6D8DB),
		  padding: EdgeInsets.symmetric(horizontal: 10.0),
		  alignment: Alignment.centerLeft,
		  child: Row(
			children: <Widget>[
			  Container(
				  child: Text(
					'PLANT',
					style: TextStyle(color: renderer.Color(0xFF212529), fontSize: 14),
				  ),
				  width: 200),
			  Container(
				  child: Text(
					'TYPE',
					style: TextStyle(color: renderer.Color(0xFF212529), fontSize: 14),
				  ),
				  width: 200),
			  Container(
				  child: Text(
					'FULLNAME',
					style: TextStyle(color: renderer.Color(0xFF212529), fontSize: 14),
				  ),
				  width: 200),
			  Container(
				  child: Text(
					'FULLNAME 3',
					style: TextStyle(color: renderer.Color(0xFF212529), fontSize: 14),
				  ),
				  width: 200),
			  Container(
				  child: Text(
					'FULLNAME 2',
					style: TextStyle(color: renderer.Color(0xFF212529), fontSize: 14),
				  ),
				  width: 200),
			  Container(
				  child: Text(
					'FULLNAME 3',
					style: TextStyle(color: renderer.Color(0xFF212529), fontSize: 14),
				  ),
				  width: 200)
			],
		  ),
		),
		content: SingleChildScrollView(
		  child: Column(
			children: _plantOperatorEmployeeData
				.map(
				  (itemRow) => Row(
						children: [

						  Container(
							  padding: EdgeInsets.all(10.0),
							  child: Text(
								'AAAAAA BBBBBB',
								style: TextStyle(color: Colors.green, fontSize: 14),
							  ),
							  width: 200),
						  Container(
							  padding: EdgeInsets.all(10.0),
							  child: Text(
								'AAAAAA BBBBBB',
								style: TextStyle(color: Colors.green, fontSize: 14),
							  ),
							  width: 200),
						  Container(
							  padding: EdgeInsets.all(10.0),
							  child: Text(
								'AAAAAA BBBBBB',
								style: TextStyle(color: Colors.green, fontSize: 14),
							  ),
							  width: 200),
						  Container(
							  padding: EdgeInsets.all(10.0),
							  child: Text(
								'AAAAAA BBBBBB',
								style: TextStyle(color: Colors.green, fontSize: 14),
							  ),
							  width: 200),
						  Container(
							  padding: EdgeInsets.all(10.0),
							  child: Text(
								'AAAAAA BBBBBB',
								style: TextStyle(color: Colors.green, fontSize: 14),
							  ),
							  width: 200),
						  Container(
							  padding: EdgeInsets.all(10.0),
							  child: Text(
								'AAAAAA BBBBBB',
								style: TextStyle(color: Colors.green, fontSize: 14),
							  ),
							  width: 200),
						],
					  ),
				)
				.toList(),
		  ),
		),
	  )
	],
  ),
),

Thank you so much.

Headers are jumping while scroll in reverse direction

So case here. I need to build infinite list in both directions (aka Schedule view in Google calendar app). Headers are positioning correctly when only forward or only reverse list is visible inside Viewport. But when both lists are shown - sticky header start to jumping during scroll. It seems that position is calculating with delay or calculating in a wrong way.

Code sample

              CustomScrollView(
                center: _centerKey, // UniqueKey()
                slivers: <Widget>[
                  SliverList(
                    delegate: SliverChildBuilderDelegate(
                      (BuildContext context, int index) {
                        return StickyHeader(
                          header: new Container(
                            height: 50.0,
                            color: Colors.blueGrey[700],
                            padding: new EdgeInsets.symmetric(horizontal: 16.0),
                            alignment: Alignment.centerLeft,
                            child: new Text('Header #$index',
                              style: const TextStyle(color: Colors.white),
                            ),
                          ),
                          content: new Container(
                            child: Text("Content #$index"),
                            color: Colors.orange,
                            height: 400,
                            width: double.infinity,
                          ),
                        );
                      },
                    ),
                  ),
                  SliverList(
                    key: _centerKey,
                    delegate: SliverChildBuilderDelegate(
                      (BuildContext context, int index) {
                        return StickyHeader(
                          header: new Container(
                            height: 50.0,
                            color: Colors.blueGrey[700],
                            padding: new EdgeInsets.symmetric(horizontal: 16.0),
                            alignment: Alignment.centerLeft,
                            child: new Text('Header #$index',
                              style: const TextStyle(color: Colors.white),
                            ),
                          ),
                          content: new Container(
                            child: Text("Content #$index"),
                            color: Colors.orange,
                            height: 400,
                            width: double.infinity,
                          ),
                        );
                      },
                    ),
                  )
                ],
              ),

And some issue visualization: https://i.ibb.co/ZLJvwsG/sticky-jump.gif

Use scrollController instead of ScrollableState

Hey cool work.

I would like to suggest to allow passing a scrollController instead of acquiring the scrollable from the context.
The reason i mostly need this is when i have a nested scrollview and i want the stickiness to happen on the top level scrollview's state.

( I have a working example of this, i could do a PR if you are interested )

Sparse header setup not working currently

Given code like this:

ListView.builder(
  itemCount: 35,
  itemBuilder: (context, i) {
    final tile = ListTile(title: Text("My Tile"));

    if (i % 5 == 0) {
      return StickyHeader(
        content: tile,
        header: Container(
          padding: EdgeInsets.symmetric(
            horizontal: 16.0,
            vertical: 8.0,
          ),
          alignment: Alignment.centerLeft,
          decoration: BoxDecoration(color: Colors.lightGreen),
          child: Text("Section"),
        ),
      );
    }

    return tile;
  }
);

Then I would expect the header stay on top of the list until the next header replaces it. Currently, it will only stay for as long as the current item stays on screen.

Blinking 1px line above the sticky header

First off, huge thanks for this plugin. Big big help!

Tiny bug: When scrolling there is a 1px line above the header. See here: https://share.icloud.com/photos/00iofG5V2K9aKDL6Mb2gZ8uKg

demostration: https://share.icloud.com/photos/0O38S_lN4_3i1TAmXjyu22QiQ

Here is the code:

Expanded(
                child: ListView.builder(
                  itemCount: 1,
                  itemBuilder: (BuildContext context, int index) {
                    return Column(
                      children: <Widget>[
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.stretch,
                          children: <Widget>[
                            ByCategory(category: 'WORLD'),
                            SizedBox(
                              height: grid1,
                            ),
                            WorldRow1(),
                            Row(
                              mainAxisAlignment: MainAxisAlignment.spaceAround,
                              children: <Widget>[
                                WorldRow3(
                                  statusColor: themeOrange,
                                  title: 'ACTIVE',
                                ),
                                SizedBox(
                                  width: grid2,
                                ),
                                WorldRow3(
                                  statusColor: themeRed,
                                  title: 'DIED',
                                ),
                                SizedBox(
                                  width: grid2,
                                ),
                                WorldRow3(
                                  statusColor: themeGreen,
                                  title: 'RECOVERED',
                                ),
                              ],
                            ),
                          ],
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: grid7),
                          child: StickyHeader(
                            header: Container(
                              padding: EdgeInsets.only(top: 88.0),
                              decoration: BoxDecoration(
                                color: themeBackgroundColor,
                                borderRadius: BorderRadius.only(
                                  bottomLeft: Radius.circular(grid2),
                                  bottomRight: Radius.circular(grid2),
                                ),
                              ),
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.stretch,
                                children: <Widget>[
                                  ByCategory(category: 'BY COUNTRY'),
                                  SizedBox(
                                    height: grid1,
                                  ),
                                  CountriesTableHeader(),
                                ],
                              ),
                            ),
                            content: Column(
                              children: <Widget>[
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                                CountryRow(),
                              ],
                            ),
                          ),
                        ),
                      ],
                    );
                  },
                ),
              ),

State snapable ?

Sticky is always the same but should be different when it is "snap on the top" and when it is not.

EXAMPLE: how to do nesting with this plugin

import 'package:flutter/material.dart';
import 'package:sticky_headers/sticky_headers/widget.dart';

//-----Start App
void main() => runApp(MyApp());

//-----Entry Point
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StatelessLink();
  }
}

//-----Statless Link Required Between Entry Point And App
class StatelessLink extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Nested Picker Link',
      home: Test(),
    );
  }
}

//-----Test Widget
class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  @override
  Widget build(BuildContext context) {
    double toolBarSize = 50;
    double sectionSize = 45;

    Widget toolBar = Container(
      width: MediaQuery.of(context).size.width,
      height: toolBarSize,
      color: Colors.red.withOpacity(1),
      child: Text("tool bar"),
    );

    Widget banner = Container(
      width: MediaQuery.of(context).size.width,
      height: 100,
      color: Colors.white,
      child: Text("banner"),
    );

    Widget subSection = StickyHeaderBuilder(
      builder: (context, stuckAmount) {
        stuckAmount = stuckAmount.clamp(0.0, 1.0);
        return Padding(
          padding: EdgeInsets.only(top: (toolBarSize + sectionSize) * (1.0 - stuckAmount)),
          child: Container(
            color: Colors.teal,
            width: MediaQuery.of(context).size.width,
            height: 26,
            child: Text("subsection"),
          ),
        );
      },
      content: Container(
        color: Colors.grey,
        width: MediaQuery.of(context).size.width,
        height: 38,
        child: Text("section body"),
      ),
    );

    Widget aSection = StickyHeaderBuilder(
      builder: (context, stuckAmount) {
        stuckAmount = stuckAmount.clamp(0.0, 1.0);
        return Padding(
          padding: EdgeInsets.only(top: toolBarSize * (1.0 - stuckAmount)),
          child: Container(
            color: Colors.pink,
            width: MediaQuery.of(context).size.width,
            height: sectionSize,
            child: Text("section"),
          ),
        );
      },
      content: Container(
        color: Colors.yellow,
        width: MediaQuery.of(context).size.width,
        height: 500,
        child: Container(
          padding: EdgeInsets.all(32),
          child: Column(
            children: [
              subSection,
              subSection,
              subSection,
            ]
          ),
        ),
      ),
    );

    return Scaffold(
      backgroundColor: Theme.of(context).primaryColorDark,
      body: SafeArea(
        child: CustomScrollView(
          slivers: <Widget>[
            SliverList(
              delegate: SliverChildListDelegate([
                banner,
                StickyHeaderBuilder(
                  builder: (context, stuckAmount) {
                    return toolBar;
                  },
                  content: Container(
                    padding: EdgeInsets.all(32),
                    child: Column(
                      children: [
                        aSection,
                        aSection,
                        aSection,
                      ]
                    ),
                  ),
                ),
              ]),
            ),
          ]
        ),
      ),
    );
  }
}

Silent exception occurring when build StickyHeaders.

NoSuchMethodError (NoSuchMethodError: The method '-' was called on null. Receiver: null

Intro

Hi, my team is facing an exception when building a list of StickyHeader. The exception does not affect the user but is polluting our crashlytics.

Images

image
image

To reproduce:

Additional Information

  • Flutter Doctor:
Running flutter doctor...
Doctor summary (to see all details, run flutter doctor -v):
[โœ“] Flutter (Channel stable, 1.20.3, on Mac OS X 10.15.6 19G2021, locale pt-BR)
[โœ“] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[โœ“] Xcode - develop for iOS and macOS (Xcode 11.7)
[โœ“] Android Studio (version 3.6)
[โœ“] VS Code (version 1.48.2)
[โœ“] Connected device (2 available) 

Sticky Header Crash

Screen Shot 2020-10-29 at 07 11 04

Screen Shot 2020-10-29 at 07 27 12

Screen Shot 2020-10-29 at 07 15 36

if itemCount set to 2, will cause crash.

Widget _buildBody(BuildContext context) {
    return ListView.builder(
      controller: _scrollController,
      physics: BouncingScrollPhysics(),
      itemCount: 2,
      itemBuilder: (context, index) {
        return StickyHeader(
          overlapHeaders: true,
          header: Container(
            height: 50.0,
            color: MyColors.lightGrayColor,
            padding: EdgeInsets.symmetric(horizontal: 16.0),
            alignment: Alignment.centerLeft,
            child: Text('Header #$index',
              style: const TextStyle(color: Colors.white),
            ),
          ),
          content: _buildContent(context),
        );
      },
    );
  }

  Widget _buildContent(BuildContext context) {
    return GridView.builder(
      controller: _scrollController,
      shrinkWrap: true,
      physics: BouncingScrollPhysics(),
      itemCount: 30,
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        mainAxisSpacing: 1,
        crossAxisSpacing: 1,
        childAspectRatio: 1,
      ), 
      itemBuilder: (BuildContext context, int index) {
        return Container(
          height: 44,
          color: MyColors.backgroundColor,
          child: Text(index.toString()),
        );
      },
    );
  }

@brianegan , pls help to check this crash. Thanks a lot!

Sticky Header Not Stick on Top

Sticky Header Not Stick on Top

Images

Screenshot_1603361527

Screenshot_1603361536

Step To Reproduce

  1. ListView Builder with Sticky Header
  2. At the end of content put form
  3. Scroll down to form and tap/focus on any input box keyboard will show.
  4. After the keyboard opens just close using the android navigation return key.
  5. Sticky header will show in the middle of the screen.

My Sample Code

ListView.builder(
                  itemCount: 1,
                  controller: _scrollController,
                  physics: BouncingScrollPhysics(),
                  itemBuilder: (context, index) {
                    return StickyHeader(
                      overlapHeaders: true,
                      header: Material(
                        color: AppColors.White,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.zero,
                        ),
                        child: Padding(
                          padding: EdgeInsets.all(10),
                          child: Row(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            mainAxisAlignment: MainAxisAlignment.start,
                            mainAxisSize: MainAxisSize.max,
                            children: [
                              InkWell(
                                child: Padding(
                                  padding: EdgeInsets.all(10),
                                  child: Icon(
                                    Icons.comment,
                                    color: AppColors.Red,
                                  ),
                                ),
                                splashColor: AppColors.Red.withOpacity(0.5),
                                onTap: () {
                                  setState(() {
                                    _shareYourThoughts = true;
                                  });
                                  var scrollPosition = _scrollController.position;
                                  if (scrollPosition.viewportDimension < scrollPosition.maxScrollExtent) {
                                    _scrollController.animateTo(
                                      scrollPosition.maxScrollExtent,
                                      duration: new Duration(milliseconds: 200),
                                      curve: Curves.easeOut,
                                    );
                                  }
                                },
                              ),
                              InkWell(
                                child: Padding(
                                  padding: EdgeInsets.all(10),
                                  child: Icon(
                                    Icons.email,
                                    color: AppColors.Red,
                                  ),
                                ),
                                splashColor: AppColors.Red.withOpacity(0.2),
                                onTap: () {},
                              ),
                              InkWell(
                                child: Padding(
                                  padding: EdgeInsets.all(10),
                                  child: Icon(
                                    Icons.file_download,
                                    color: AppColors.Red,
                                  ),
                                ),
                                splashColor: AppColors.Red.withOpacity(0.2),
                                onTap: () async {
                                  var status = await Permission.storage.status;
                                  if (status.isGranted) {
                                    var listDirectories = await _requestExternalStorageDirectory();
                                    if (listDirectories != null) {
                                      _applicationDocumentDirectory = listDirectories[0];
                                    }
                                    if (_applicationDocumentDirectory != null) {
                                      Directory appDownload = Directory(_applicationDocumentDirectory.path);
                                      taskId = await FlutterDownloader.enqueue(
                                        url: postDownloadUrl,
                                        savedDir: appDownload.path,
                                        showNotification: true, // show download progress in status bar (for Android)
                                        openFileFromNotification: true, // click on notification to open downloaded file (for Android)
                                      );
                                    }
                                  }
                                },
                              )
                            ],
                          ),
                        ),
                      ),
                      content: Padding(
                        padding: EdgeInsets.all(20),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          mainAxisAlignment: MainAxisAlignment.start,
                          mainAxisSize: MainAxisSize.max,
                          children: [
                            CategoryButton(
                              category: postCategory,
                              categoryId: state.post.catId,
                            ),
                            Padding(
                              padding: const EdgeInsets.only(top: 10, bottom: 10),
                              child: Text(
                                postTitle,
                                style: TextStyle(
                                  color: AppColors.Black,
                                  fontFamily: AppFonts.Font_Family,
                                  fontWeight: FontWeight.bold,
                                  letterSpacing: 0.1,
                                  shadows: [
                                    Shadow(
                                      blurRadius: 0.1,
                                    )
                                  ],
                                  fontSize: 24,
                                ),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(bottom: 10),
                              child: Text(
                                DateFormat.yMMMMd().format(DateTime.parse(postDate)),
                                style: TextStyle(
                                  color: AppColors.Grey,
                                  fontFamily: AppFonts.Font_Family,
                                  fontWeight: FontWeight.normal,
                                  letterSpacing: 0.1,
                                  shadows: [
                                    Shadow(
                                      blurRadius: 0.1,
                                    )
                                  ],
                                  fontSize: 18,
                                ),
                              ),
                            ),
                            Html(
                              data: postContent,
                              onLinkTap: AppNavigation.launchUrl,
                              style: {
                                "p": Style(
                                  color: AppColors.Black,
                                  fontFamily: AppFonts.Font_Family,
                                  fontWeight: FontWeight.w400,
                                  letterSpacing: 0.1,
                                  textShadow: [
                                    Shadow(
                                      blurRadius: 0.1,
                                    )
                                  ],
                                  fontSize: FontSize(18),
                                  padding: EdgeInsets.all(0),
                                ),
                                "a": Style(
                                  textDecoration: TextDecoration.none,
                                  color: AppColors.Red,
                                  fontFamily: AppFonts.Font_Family,
                                  fontWeight: FontWeight.w400,
                                  letterSpacing: 0.1,
                                  textShadow: [
                                    Shadow(
                                      blurRadius: 0.1,
                                    )
                                  ],
                                  fontSize: FontSize(18),
                                  padding: EdgeInsets.all(0),
                                ),
                                "li": Style(
                                  color: AppColors.Black,
                                  fontFamily: AppFonts.Font_Family,
                                  fontWeight: FontWeight.w400,
                                  letterSpacing: 0.1,
                                  textShadow: [
                                    Shadow(
                                      blurRadius: 0.1,
                                    )
                                  ],
                                  fontSize: FontSize(18),
                                  padding: EdgeInsets.only(
                                    top: 5,
                                    bottom: 2.5,
                                  ),
                                ),
                              },
                            ),
                            InkWell(
                              splashColor: AppColors.Red.withOpacity(0.2),
                              onTap: () {
                                setState(() {
                                  _shareYourThoughts = true;
                                });
                              },
                              child: Padding(
                                padding: const EdgeInsets.only(top: 10, bottom: 10),
                                child: Text(
                                  "Share your thoughts",
                                  style: TextStyle(
                                    color: AppColors.Red,
                                    fontFamily: AppFonts.Font_Family,
                                    fontWeight: FontWeight.normal,
                                    letterSpacing: 0.1,
                                    shadows: [
                                      Shadow(
                                        blurRadius: 0.1,
                                      )
                                    ],
                                    fontSize: 18,
                                  ),
                                ),
                              ),
                            ),
                            if (_shareYourThoughts)
                              Form(
                                key: _formKey,
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  mainAxisSize: MainAxisSize.max,
                                  children: [
                                    InputBox(
                                      inputType: TextInputType.name,
                                      labelText: "Name",
                                      currentFocusNode: _nameFocus,
                                      nextFocusNode: _emailFocus,
                                      validator: (value) {
                                        if (value.isEmpty) {
                                          return 'Please enter name';
                                        }
                                        return null;
                                      },
                                    ),
                                    InputBox(
                                        inputType: TextInputType.emailAddress,
                                        labelText: "Email",
                                        currentFocusNode: _emailFocus,
                                        nextFocusNode: _websiteFocus,
                                        validator: (value) {
                                          if (value.isEmpty) {
                                            return 'Please enter email';
                                          }
                                          return null;
                                        }),
                                    InputBox(
                                        inputType: TextInputType.url,
                                        labelText: "Website",
                                        currentFocusNode: _websiteFocus,
                                        nextFocusNode: _commentFocus,
                                        validator: (value) {
                                          if (value.isEmpty) {
                                            return 'Please enter website url';
                                          }
                                          return null;
                                        }),
                                    InputBox(
                                      inputType: TextInputType.multiline,
                                      labelText: "Comment",
                                      currentFocusNode: _commentFocus,
                                      isLastFocus: true,
                                      validator: (value) {
                                        if (value.isEmpty) {
                                          return 'Please enter comment';
                                        }
                                        return null;
                                      },
                                      maxLength: 200,
                                    ),
                                    RaisedButton(
                                      onPressed: () {
                                        if (_formKey.currentState.validate()) {
                                          // If the form is valid, display a Snackbar.
                                          Scaffold.of(context).showSnackBar(SnackBar(content: Text('Processing Data')));
                                        }
                                      },
                                      child: Text(
                                        "Submit",
                                        style: TextStyle(
                                          fontFamily: AppFonts.Font_Family,
                                          fontWeight: FontWeight.normal,
                                          letterSpacing: 0.1,
                                          shadows: [
                                            Shadow(
                                              blurRadius: 0.1,
                                            )
                                          ],
                                          fontSize: 18,
                                        ),
                                      ),
                                    )
                                  ],
                                ),
                              ),
                          ],
                        ),
                      ),
                    );
                  },
                );

Unhandled exception: setState() called after dispose()

Simon, I get this if I scroll the list fast enough:

Unhandled exception:
E/flutter ( 4840): setState() called after dispose(): _StickyHeaderBuilderState#2ad9c(lifecycle state: defunct, not mounted)
_StickyHeaderBuilderState.build.<anonymous closure>.<anonymous closure> (package:sticky_headers/sticky_headers/widget.dart:121:58)

It tells me this:

*This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.

E/flutter ( 4840): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().*

I believe the item is being removed from the tree (because of scrolling) before the next frame is displayed.

Is there a way to be optional a header?

I have a list with a date field. I want to group several items in a same header. Is it possible?
Example:
Header
content
content --> no header
Header
content
Header
content
content --> no header
content --> no header
...

I tried "head: condition ? widget : null" but it does not render.

Thanks!

Thank you!

I've already wanted this functionality months ago (actually somewhen in 2017) and tried to implement it by myself but didn't come up with a working solution.
Just discovered this plugin so I just wanted to say thank you, thanks a lot!

Scrolling under SliverAppBar with NestedScrollView

I basically took the example from the NestedScrollView description Here and made minimal modifications (replaced fixed extent sliver list with a normal sliver list) and added in the sticky header builder widget.

The headers seem to scroll under the SliverAppBar.

Can this be fixed? Any workarounds? I know putting the AppBar in a SliverSafeArea can fix it but it makes the animations janky.

ezgif com-video-to-gif

Shadow when header is overlapping content?

It would be nice if there was a slight shadow when the content scrolls under the sticky header.

So, as a sticky header scrolls up to the top, it's at the same elevation as the content and casts no shadow, but when it sticks at the top and the content scrolls under it, it should raise in elevation and a slight shadow should be displayed.

The previous top header that is being pushed off should be at the same elevation as the new header and should not cast a shadow on the new header that is pushing it off.

Bonus points for letting me specify the elevation and thus the shadow depth.

reverse

Implement reverse list support would be nice. Especially for chats.

TabBar

Hi doesn't work with tabbar

Is there a way to have multiple content under one StickyHeader?

Is there a way to have more than one content for one StickyHeader?

As of right now, I can only manage to get one ListTile widget underneath a StickyHeader widget. But I want to make a single ListView with two StickyHeader widgets and five ListTile widgets underneath each StickyHeader widget -- is that possible?

Thank you in advance @slightfoot for any help you can provide!

one way to fixed sliver app bar overlap

// find sliverlist renderobject
    RenderSliver? renderSliver  = context.findAncestorRenderObjectOfType<RenderSliver>();  

// determineStuckOffset
  double determineStuckOffset() {
    double dy;

    try {
      dy = localToGlobal(Offset(0, -renderSliver.constraints.overlap), ancestor: renderSliver).dy;
    } catch (e) {
      // ignore and fall-through and return 0.0
      dy = 0.0;
    }
    return dy;
  }

Not working with CupertinoSliverNavigationBar

Hey I use the following layout:

  @override
  Widget build(BuildContext context) {
    return new CupertinoPageScaffold(
      child: new CustomScrollView(
        slivers: <Widget>[
          CupertinoSliverNavigationBar(
            largeTitle: new Text('Title'),
          ),
          CupertinoRefreshControl(onRefresh: () {
            Future<void> future = requestApi();
            return future;
          }),
          SliverSafeArea(
            sliver: SliverList(
              delegate: SliverChildListDelegate(
                new StickyHeader(
                   header: DateView(
                      date: entryList[i]["day"] + ", " + entryList[i]["date"],
                   ),
                   content: Column(
                      children: dateWidgets,
                ),
            ),
              ),
            ),
          )
        ],
      ),
    );
  }

Widgets is a list with StickyHeaders. And in this configuration the headers aren't sticky. But when I remove the CupertinoSliverNavigationBar it works.

Jumpt to offset messes up the headers.

I created a new flutter project and added

sticky_headers:

Afterwards I implemented a list builder that has a ScrollController.
I call setState 3 times at a 5 seconds interval and modify a global offset variable which will be used on the build method to jump the list to a new offset (using SchedulerBinding.instance.addPostFrameCallback).

The problem is that after I call the jumpto method, the headers are messed up ( if I manual scroll the headers will come back to a normal position).

Example:

ezgif com-video-to-gif (1)

The code:

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:sticky_headers/sticky_headers.dart';

double offset = 0;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration(seconds: 5)).then((_) => setState(() {
      offset = 3000;
    })).then((_) async => await Future.delayed(Duration(seconds: 5))).then((_) => setState(() {
      offset = 1000;
    })).then((_) async => await Future.delayed(Duration(seconds: 5))).then((_) => setState(() {
      offset = 5000;
    }));
  }

  @override
  Widget build(BuildContext context) {
    SchedulerBinding.instance.addPostFrameCallback((_) {
      print(offset);
      _scrollController.jumpTo(offset);
    });
    return Scaffold(body: Container(padding: EdgeInsets.only(top: 20),child: _buildList(context)));
  }

  Widget _buildList(BuildContext context) {
    return NotificationListener<ScrollNotification>(
        child: ListView.builder(
            controller: _scrollController,
            itemCount: 100,
            itemBuilder: (BuildContext context, int sectionIndex) => StickyHeader(
                header: Container(
                    height: 50,
                    alignment: Alignment.center,
                    color: Colors.blue,
                    child: Text("$sectionIndex")),

                content: ListView.builder(
                    itemCount: 10,
                    shrinkWrap: true,
                    physics: NeverScrollableScrollPhysics(),
                    itemBuilder: (context, rowIndex) => Container(
                        color: Colors.white,
                        child: Text("$sectionIndex"))))),

        onNotification: (ScrollNotification scrollNotification) {
          offset = _scrollController.offset;
          print(offset);
          return true;
        });
  }
}

Content should not go bellow header if overlapHeaders: false

Currently when scrolling some list and we have a sticky header in it, all content goes bellow header. Expectation is that content goes up until the header and then disappears.

This is especially important if a header doesn't have background color (transparent) which currently is not possible to have because of the issue i described.

Can not add tap event handler on header, if content is SizedBox.shrink()

        StickyHeader(
          header: Tappable(
            child: Container(
              height: appThemeData.mainPadding * 2.5,
              padding: EdgeInsets.symmetric(
                horizontal: appThemeData.mainPadding,
                vertical: appThemeData.halfPadding,
              ),
              color: Colors.white,
              width: double.infinity,
              child: Text(title.toUpperCase(), style: textStyle),
            ),
            onTap: () {
              print('StickyHeader - Tappable.onTap()');
            },
          ),
          content: SizedBox.shrink(),
        )

Remain stuck to the bottom

Will layout the header above the content unless the overlapHeaders boolean is set to true. The header will remain stuck to the top of its parent Scrollable content.

Is it possible to remain stuck to the bottom of scrollable content while overlapHeaders is true

is it possible to create sticky footer ?

your method is amazing !
would be nice to add ability like behavior footer.

it would be more useful than header especially for call to action button likes "checkout", "add to cart" button
which will be scroll up like other list element but pin to bottom when scroll down.

A ScrollPositionWithSingleContext was used after being disposed.

The following assertion was thrown building RawGestureDetector-[LabeledGlobalKey#bc1b8](state: RawGestureDetectorState#1c9cc(gestures: [vertical drag], behavior: opaque)):
A ScrollPositionWithSingleContext was used after being disposed.

Once you have called dispose() on a ScrollPositionWithSingleContext, it can no longer be used.
The relevant error-causing widget was:

Provide support for Flutter Web

At first: Thank you so much for this package! Great one!

But i was disappointed, when I saw, that the package in pub.dev is not available for flutter web. Here's just only dart code and no native code.

Could you please update the package, so that it is available for Web?

Thank you so much ๐Ÿ˜Š

What is the best practice on a large amount of items in content?

I use StickyHeader to make iOS-TableView-like UI and add Column of my widgets StickyHeader's content.
But I suppose that the bigger the size of widgets, the less its rendering performance.
Is there any ways like ListView.builder, which render just visible widgets instead of all ones?

Maybe related to #3.

StickyHeaderBuilder vs StickyHeader

I first thought StickyHeaderBuilder is a replacement for LisView.Builder but example app use it inside ListView.builder so what's the difference between these 2?

Pin sticky headers on top when adding slivers to a reverse CustomScrollView or ListView

Hi,

I am implementing a chat widget and using your library to separate messages by date, you can see the same behavior on Whatsapp and Telegram.

I am building several slivers that each contain messages on that date and a header which is basically a text showing the relevant date. I pass the slivers to a CustomScrollView with reverse property set to true.

Everything works fine except that the headers are pinned to the bottom of the screen (I need them to stick to the top).
How can I fix this? Any pointers would be appreciated.

.
.
.
   return CustomScrollView(
      slivers: _buildListItem(context, sectionIndex),
      reverse: false,
      controller: listScrollController,
    );
.
.
.
  List<Widget> _buildListItem(
    BuildContext context,
    List<ChatSection> chatSections,
  ) {
    List<Widget> slivers = List();
    chatSections.forEach((chatSection) {
      slivers.add(_buildChatSliver(
          context, chatSection.messages, chatSection.datetime));
    });

    return slivers;
  }
  SliverStickyHeaderBuilder _buildChatSliver(BuildContext context,
      List<ChatMessage> chatMessages, DateTime dateTimeHeader) {
    return SliverStickyHeaderBuilder(
      overlapsContent: false,
      builder: (context, state) {
        DateTime now = DateTime.now();
        String headerText = now.year != dateTimeHeader.year
            ? DateFormat("YYYY MMM dd").format(dateTimeHeader)
            : DateFormat("MMM dd").format(dateTimeHeader);
        return Container(
          padding: EdgeInsets.fromLTRB(5, 0, 15, 5),
          child: Center(
            child: Container(
              padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
              decoration: BoxDecoration(
                  color: Color.fromARGB(200, 150, 150, 150),
                  borderRadius: BorderRadius.all(Radius.circular(5))),
              child: Text(
                headerText,
                style: TextStyle(
                    color: Colors.white70,
                    fontSize: 12.0,
                    fontStyle: FontStyle.italic),
              ),
            ),
          ),
        );
      },
      sliver: SliverList(
          delegate: SliverChildBuilderDelegate(
              (context, i) => _buildItem(chatMessages[i]),
              childCount: chatMessages.length)),
    );
  }

Wobbly headers when used along `infinite_listview`

When using this library along with infinite_listview, some headers of the negative indexes get flicky. It happens until the index 0 is visible, then it stops.

You should be able to see some blank spaces between some headers and the AppBar:

ezgif com-video-to-gif

The code used in the example above:

import 'package:flutter/material.dart';
import 'package:infinite_listview/infinite_listview.dart';
import 'package:sticky_headers/sticky_headers.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Example(),
      theme: ThemeData(primarySwatch: Colors.blueGrey),
    );
  }
}

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Example'),
      ),
      body: InfiniteListView.builder(
        itemBuilder: (_, int index) {
          return StickyHeader(
            header: header(context),
            content: ListTile(
              title: Text('Item #$index'),
              subtitle: Text('Description'),
            ),
          );
        },
      ),
    );
  }

  Container header(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      width: double.infinity,
      color: Colors.blueGrey[700],
      child: Text(
        'Header',
        style: Theme.of(context).textTheme.title.copyWith(color: Colors.white),
      ),
    );
  }
}

version 0.1.8+1 App crash flash back

W/libc (11551): malloc(18446744073709551615) failed: returning null pointer
F/libc (11551): Fatal signal 11 (SIGSEGV), code 128 (SI_KERNEL), fault addr 0x0 in tid 11579 (1.ui), pid 11551 (com.tianyu.tyjr)


Build fingerprint: 'google/sdk_gphone_x86_64_arm64/generic_x86_64_arm64:11/RSR1.201013.001/6903271:userdebug/dev-keys'
Revision: '0'
ABI: 'x86_64'
Timestamp: 2021-10-09 19:17:23+0800
pid: 11551, tid: 11579, name: 1.ui >>> com.tianyu.tyjr <<<
uid: 10156
signal 11 (SIGSEGV), code 128 (SI_KERNEL), fault addr 0x0
rax 0000746a7f1b6540 rbx 0006e04c0001d340 rcx 00007468e3cf9451 rdx 0014a0e4000579c0
r8 00007ffd5350d0a8 r9 00007468e011e0a9 r10 00007ffd5350d080 r11 0000000000000246
r12 3360020800000000 r13 00007468f6aefb30 r14 0000746a7f1b6510 r15 0000746a7f1b6530
rdi 0000746a7f1b5e20 rsi 00000000000000c0
rbp 0000746a7f1b6520 rsp 00007468f6aefaa0 rip 00007468f6362657
backtrace:
#00 pc 0000000001753657 /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#1 pc 0000000001751387 /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#2 pc 0000000001742bca /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#3 pc 000000000174a83b /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#4 pc 000000000175638d /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#5 pc 0000000001756330 /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#6 pc 0000000001756304 /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#7 pc 000000000185b0ba /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#8 pc 0000000001852cd9 /data/app/~~NWOuiwIFiaqYHgY2h3zwmg==/com.app.app-AdmQaszwB4dm8UzMpCbMVQ==/lib/x86_64/libflutter.so (BuildId: 22527e02903e18498db02e010efdc0ab2dc3010c)
#9 pc 0000000000001412 anonymous:7468f3280000
Lost connection to device.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.