【问题标题】:Allow GridView to overlap SliverAppBar允许 GridView 与 SliverAppBar 重叠
【发布时间】:2019-05-11 14:00:40
【问题描述】:

我正在尝试从早期的 Material Design 规范中重现以下示例(打开动画演示):

到目前为止,我能够产生滚动效果,但内容的重叠仍然缺失。我不知道如何正确执行此操作。

import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            title: Text('Title'),
            expandedHeight: 200.0,
            primary: true,
            pinned: true,
          ),
          SliverFixedExtentList(
            itemExtent: 30.0,
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int i) => Text('Item $i')
            ),
          ),
        ],
      ),
    );
  }
}

【问题讨论】:

  • 原始 gif/动画是什么?
  • 点击截图/图片即可打开原动画webp。
  • 嗨,你曾经能重现这个吗?如果有,介意分享吗?

标签: flutter flutter-sliver


【解决方案1】:

我遇到了同样的问题,但无法用条子解决它。这个来自另一个 stackoverflow 问题的例子解决了我的问题。

flutter - App bar scrolling with overlapping content in Flexible space

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Scroll demo',
      home: new Scaffold(
        appBar: new AppBar(elevation: 0.0),
        body: new CustomScroll(),
      ),
    );
  }
}

class CustomScroll extends StatefulWidget {
  @override
  State createState() => new CustomScrollState();
}

class CustomScrollState extends State<CustomScroll> {
  ScrollController scrollController;
  double offset = 0.0;
  static const double kEffectHeight = 100.0;

  @override
  Widget build(BuildContext context) {
    return new Stack(
      alignment: AlignmentDirectional.topCenter,
      children: <Widget> [
        new Container(
          color: Colors.blue,
          height: (kEffectHeight - offset * 0.5).clamp(0.0, kEffectHeight),
        ),
        new Positioned(
          child: new Container(
            width: 200.0,
            child: new ListView.builder(
              itemCount: 100,
              itemBuilder: buildListItem,
              controller: scrollController,
            ),
          ),
        ),
      ],
    );
  }

  Widget buildListItem(BuildContext context, int index) {
    return new Container(
      color: Colors.white,
      child: new Text('Item $index')
    );
  }

  void updateOffset() {
    setState(() {
      offset = scrollController.offset;
    }); 
  }

  @override
  void initState() {
    super.initState();
    scrollController = new ScrollController();
    scrollController.addListener(updateOffset);
  }

  @override
  void dispose() {
    super.dispose();
    scrollController.removeListener(updateOffset);
  }
}

将列表更改为网格及其所需的内容

【讨论】:

    【解决方案2】:

    我使用ScrollController 和一些技巧设法获得了这个功能:

    代码如下:

      ScrollController _scrollController;
      static const kHeaderHeight = 235.0;
    
      double get _headerOffset {
        if (_scrollController.hasClients) if (_scrollController.offset > kHeaderHeight)
          return -1 * (kHeaderHeight + 50.0);
        else
          return -1 * (_scrollController.offset * 1.5);
    
        return 0.0;
      }
    
      @override
      void initState() {
        super.initState();
    
        _scrollController = ScrollController()..addListener(() => setState(() {}));
      }
    
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return StackWithAllChildrenReceiveEvents(
          alignment: AlignmentDirectional.topCenter,
          children: [
            Positioned(
              top: _headerOffset,
              child: Container(
                height: kHeaderHeight,
                width: MediaQuery.of(context).size.width,
                color: Colors.blue,
              ),
            ),
            Padding(
              padding: EdgeInsets.only(left: 20.0, right: 20.0),
              child: Feed(controller: _scrollController, headerHeight: kHeaderHeight),
            ),
          ],
        );
      }
    

    为了使Feed() 不与蓝色容器重叠,我只是将它的第一个子元素设为SizedBox 并具有所需的高度属性。

    请注意,我使用的是修改后的 Stack 类。那是为了让堆栈中的第一个小部件(蓝色容器)检测压力,所以它适合我的用途;不幸的是,此时默认的Stack 小部件存在问题,您可以通过https://github.com/flutter/flutter/issues/18450 了解更多信息。

    StackWithAllChildrenReceiveEvents 代码可以在https://github.com/flutter/flutter/issues/18450#issuecomment-575447316 上找到。

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 2020-11-15
      • 2021-01-22
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 2012-10-10
      相关资源
      最近更新 更多