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 People

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

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

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'
];

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;
  }

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,
                                        ),
                                      ),
                                    )
                                  ],
                                ),
                              ),
                          ],
                        ),
                      ),
                    );
                  },
                );

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(),
                              ],
                            ),
                          ),
                        ),
                      ],
                    );
                  },
                ),
              ),

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.

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;
        });
  }
}

reverse

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

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!

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)),
    );
  }

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) 

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!

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 )

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.

TabBar

Hi doesn't work with tabbar

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.

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!

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:

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!

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(),
        )

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?

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.

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),
      ),
    );
  }
}

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.

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.

State snapable ?

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

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

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.

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 ๐Ÿ˜Š

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.

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.