Atamyrat Babayev
Atamyrat Babayev

Reputation: 890

Complex sliver in CustomScrollView Flutter

Currently I have List of FeaturedBlock. Featured block contains header and list of products. So the problem is that I'm not sure how to add that block(header with gridList) to CustomScrollView. So the structure is:

--------------
|SliverAppBar|
--------------
...some elements
--------------
|   Header   |   ----> Featured Block header
--------------
------ -------
|    | |     |   ----> Featured Block products
|    | |     |
------ -------
------ -------
|    | |     |
|    | |     |
------ -------
--------------
|   Header   |  ----> Featured Block header
--------------
------ -------
|    | |     |   ----> Featured Block products
|    | |     |
------ -------
------ -------
|    | |     |
|    | |     |
------ -------

So, how to convert FeaturedBlock to Sliver element?

Upvotes: 0

Views: 963

Answers (1)

chunhunghan
chunhunghan

Reputation: 54367

You can copy paste run full code below
You can use SliverPersistentHeader and SliverGrid.count and change crossAxisCount per your request
working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'dart:math' as math;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Collapsing List Demo')),
        body: CollapsingList(),
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({
    @required this.minHeight,
    @required this.maxHeight,
    @required this.child,
  });
  final double minHeight;
  final double maxHeight;
  final Widget child;
  @override
  double get minExtent => minHeight;
  @override
  double get maxExtent => math.max(maxHeight, minHeight);
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new SizedBox.expand(child: child);
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

class CollapsingList extends StatelessWidget {
  SliverPersistentHeader makeHeader(String headerText) {
    return SliverPersistentHeader(
      pinned: true,
      delegate: _SliverAppBarDelegate(
        minHeight: 60.0,
        maxHeight: 200.0,
        child: Container(
            color: Colors.lightBlue, child: Center(child: Text(headerText))),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          title: Text('SliverAppBar'),
          backgroundColor: Colors.green,
          expandedHeight: 200.0,
          flexibleSpace: FlexibleSpaceBar(
            background: Image.network('https://picsum.photos/250?image=9',
                fit: BoxFit.cover),
          ),
        ),
        makeHeader('Header Section 1'),
        SliverGrid.count(
          crossAxisCount: 2,
          children: [
            Container(color: Colors.red, height: 150.0),
            Container(color: Colors.purple, height: 150.0),
            Container(color: Colors.green, height: 150.0),
            Container(color: Colors.orange, height: 150.0),
          ],
        ),
        makeHeader('Header Section 2'),
        SliverGrid.count(
          crossAxisCount: 2,
          children: [
            Container(color: Colors.red, height: 150.0),
            Container(color: Colors.purple, height: 150.0),
            Container(color: Colors.green, height: 150.0),
            Container(color: Colors.orange, height: 150.0),
          ],
        ),
        makeHeader('Header Section 3'),
        SliverGrid.count(
          crossAxisCount: 2,
          children: [
            Container(color: Colors.red, height: 150.0),
            Container(color: Colors.purple, height: 150.0),
            Container(color: Colors.green, height: 150.0),
            Container(color: Colors.orange, height: 150.0),
          ],
        ),
        makeHeader('Header Section 4'),
        SliverGrid.count(
          crossAxisCount: 2,
          children: [
            Container(color: Colors.red, height: 150.0),
            Container(color: Colors.purple, height: 150.0),
            Container(color: Colors.green, height: 150.0),
            Container(color: Colors.orange, height: 150.0),
          ],
        ),
      ],
    );
  }
}

working demo 2

enter image description here

full code 2

import 'package:flutter/material.dart';
import 'dart:math' as math;

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

List<Widget> widgetList = [];

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int count = 0;

  SliverPersistentHeader makeHeader(String headerText) {
    return SliverPersistentHeader(
      pinned: true,
      delegate: _SliverAppBarDelegate(
        minHeight: 60.0,
        maxHeight: 200.0,
        child: Container(
            color: Colors.lightBlue, child: Center(child: Text(headerText))),
      ),
    );
  }

  void _add() {
    count = count + 1;
    widgetList.add(makeHeader(count.toString()));
    widgetList.add(
      SliverGrid.count(
        crossAxisCount: 2,
        children: [
          Container(color: Colors.red, height: 150.0),
          Container(color: Colors.purple, height: 150.0),
          Container(color: Colors.green, height: 150.0),
          Container(color: Colors.orange, height: 150.0),
        ],
      ),
    );

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Collapsing List Demo')),
        body: CollapsingList(),
        floatingActionButton: FloatingActionButton(
          onPressed: _add,
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({
    @required this.minHeight,
    @required this.maxHeight,
    @required this.child,
  });
  final double minHeight;
  final double maxHeight;
  final Widget child;
  @override
  double get minExtent => minHeight;
  @override
  double get maxExtent => math.max(maxHeight, minHeight);
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new SizedBox.expand(child: child);
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

class CollapsingList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          title: Text('SliverAppBar'),
          backgroundColor: Colors.green,
          expandedHeight: 200.0,
          flexibleSpace: FlexibleSpaceBar(
            background: Image.network('https://picsum.photos/250?image=9',
                fit: BoxFit.cover),
          ),
        ),
        ...widgetList
      ],
    );
  }
}

Upvotes: 1

Related Questions