如何使用可滚动的小部件绘制一个具有复杂标题的UI?

时间:2019-06-21 14:34:17

标签: flutter flutter-animation

我是Flutter的新学习者。现在,我必须为一个项目实现一个UI(Link)。我认为我应该使用 CustomerScrollView NestedScrollView 完成它。我已经尽力了,但是我很讨厌实现标头 SliverAppBar ADBar 。有人可以帮忙提出一些建议吗?

我尝试使用NestedScrollView,并将所有项目放入SliverAppBar,遇到一个问题。如果我使用FlexibleSpaceBar,则在初始化时所有项目都将缩小到手机之外,直到向上滚动一段距离,您什么都看不到。如果我放弃FlexibleSpaceBar并使用普通的Widget,那似乎还可以,但是如果我向上滚动并一旦 Ad Bar 与文本项重叠,则错误“ BOTTOM OVERFLOWED XX PIXELS”将消失。 >

class _MyPageState extends State<MyPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appbar: AppBar(/*build my AppBar*/),
      body: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              ...,
              expandedHeight: 180,
              flexibleSpace: FlexibleSpaceBar(  //if use, all texts are out of phone when initializing
                                                //if not use, Error('BOTTOM OVERFLOWED xx PIXELS') while scrolling up
                title: Padding(
                  padding: EdgeInsets.all(10),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget>[
                          Text('Text 1'),
                          Text('Text 2'),
                          Text('Text 3'),
                        ],
                      ),
                      Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget>[
                          Text('Text 4'),
                          Text('Text 5'),
                          Text('Text 6'),
                        ],
                      ),
                    ],
                  )
                ),
              ),
              //implement AD Bar
              SliverPersistentHeader(
                delegate: _SliverPersistentHeaderDelegate(_buildADBar())
              ),
            )
          ];
        },
        body: //build body
          GridView.count(
            crossAxisCount: 2,
            children: ...
          ),
      ),
    );
  }
}

2 个答案:

答案 0 :(得分:0)

作为选择

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('App Bar'),
          centerTitle: true,
          elevation: 0,
        ),
        body: CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              expandedHeight: 180,
              floating: false,
              elevation: 0,
              backgroundColor: Colors.green,
              flexibleSpace: SingleChildScrollView(
                child: Padding(
                  padding: EdgeInsets.all(10),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget>[
                          Text('Text 1'),
                          Text('Text 2'),
                          Text('Text 3'),
                        ],
                      ),
                      Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget>[
                          Text('Text 4'),
                          Text('Text 5'),
                          Text('Text 6'),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
            SliverAppBar(
              pinned: true,
              elevation: 0,
              flexibleSpace: Container(
                alignment: Alignment.center,
                height: kToolbarHeight,
                color: Colors.redAccent,
                child: Text('AD Bar'),
              ),
            ),
            SliverGrid.count(
              crossAxisCount: 2,
              children: List.generate(20, (index) {
                return Card(
                  color: Colors.white,
                );
              }),
            ),
          ],
        ),
      ),
    );
  }
}

enter image description here

答案 1 :(得分:0)

这是您需要做的:

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>[
        makeHeader('Header Section 1'),
        SliverGrid.count(
          crossAxisCount: 3,
          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),
            Container(color: Colors.yellow, height: 150.0),
            Container(color: Colors.pink, height: 150.0),
            Container(color: Colors.cyan, height: 150.0),
            Container(color: Colors.indigo, height: 150.0),
            Container(color: Colors.blue, height: 150.0),
          ],
        ),
        makeHeader('Header Section 2'),
        SliverFixedExtentList(
          itemExtent: 150.0,
          delegate: SliverChildListDelegate(
            [
              Container(color: Colors.red),
              Container(color: Colors.purple),
              Container(color: Colors.green),
              Container(color: Colors.orange),
              Container(color: Colors.yellow),
            ],
          ),
        ),
        makeHeader('Header Section 3'),
        SliverGrid(
          gridDelegate: 
              new SliverGridDelegateWithMaxCrossAxisExtent(
            maxCrossAxisExtent: 200.0,
            mainAxisSpacing: 10.0,
            crossAxisSpacing: 10.0,
            childAspectRatio: 4.0,
          ),
          delegate: new SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              return new Container(
                alignment: Alignment.center,
                color: Colors.teal[100 * (index % 9)],
                child: new Text('grid item $index'),
              );
            },
            childCount: 20,
          ),
        ),
        makeHeader('Header Section 4'),
        // Yes, this could also be a SliverFixedExtentList. Writing 
        // this way just for an example of SliverList construction.
        SliverList(
          delegate: SliverChildListDelegate(
            [
              Container(color: Colors.pink, height: 150.0),
              Container(color: Colors.cyan, height: 150.0),
              Container(color: Colors.indigo, height: 150.0),
              Container(color: Colors.blue, height: 150.0),
            ],
          ),
        ),
      ],
    );
  }
}

我绝对会建议您阅读此Slivers Demystified

希望这会有所帮助。