在滚动ListView时显示和隐藏容器

时间:2019-10-06 05:47:53

标签: flutter dart flutter-layout

如何在向下滚动Container时显示带有动画的ListView并在向上滚动时将其隐藏。

我要附加的视频不是我想要的确切实现,而只是给您一个想法。

enter image description here

视频示例

https://imgur.com/a/auEzJQk


修改:

每次向下滚动时,我需要显示Container,而每次向上滚动时,我都希望将其隐藏。它不应该取决于ListView的索引。

3 个答案:

答案 0 :(得分:4)

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    const double HEIGHT = 96;
    final ValueNotifier<double> notifier = ValueNotifier(0);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: const Text('Test')),
        body: Stack(
          children: [
            NotificationListener<ScrollNotification>(
              onNotification: (n) {
                if (n.metrics.pixels <= HEIGHT) {
                  notifier.value = n.metrics.pixels;
                }
                return false;
              },
              child: ListView.builder(
                itemCount: 42,
                itemBuilder: (context, index) {
                  return Container(
                    height: 64,
                    padding: const EdgeInsets.all(16),
                    alignment: Alignment.centerLeft,
                    child: Text('Item $index'),
                  );
                },
              ),
            ),
            HideableWidget(height: HEIGHT, notifier: notifier),
          ],
        ),
      ),
    );
  }
}

class HideableWidget extends StatelessWidget {
  final double height;
  final ValueNotifier<double> notifier;

  HideableWidget({@required this.height, @required this.notifier});

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<double>(
      valueListenable: notifier,
      builder: (context, value, child) {
        return Transform.translate(
          offset: Offset(0, value - height),
          child: Container(
            height: 80,
            color: Colors.red,
          ),
        );
      },
    );
  }
}

enter image description here

答案 1 :(得分:3)

我已经解决了您的问题。这是演示代码

 class _DemoState extends State<WidgetDemo> {
      ScrollController scrollController = new ScrollController();
      bool isVisible = true;

      @override
      initState() {
        super.initState();
        scrollController.addListener(() {
          if (scrollController.position.userScrollDirection ==
              ScrollDirection.reverse) {
            if (isVisible)
              setState(() {
                isVisible = false;
              });
          }
          if (scrollController.position.userScrollDirection ==
              ScrollDirection.forward) {
            if (!isVisible)
              setState(() {
                isVisible = true;
              });
          }
        });
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Stack(
            children: <Widget>[
              new CustomScrollView(
                controller: scrollController,
                shrinkWrap: true,
                slivers: <Widget>[
                  new SliverPadding(
                    padding: const EdgeInsets.all(20.0),
                    sliver: new SliverList(
                      delegate: new SliverChildListDelegate(
                        <Widget>[
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                          const Text('My temp data'),
                          const Text('Wow its working'),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
              AnimatedContainer(
                  duration: Duration(milliseconds: 400),
                  height: isVisible ? 60.0 : 0.0,
                  child: new Container(
                    color: Colors.green,
                    width: MediaQuery.of(context).size.width,
                    child: Center(child: Text("Container")),
                  )),
            ],
          ),
        );
      }
    }

答案 2 :(得分:1)

不确定我是否正确回答了您的问题,这是您要实现的目标吗?

截屏:

enter image description here


代码:

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Height of your Container
  static final _containerHeight = 100.0;

  // You don't need to change any of these variables
  var _fromTop = -_containerHeight;
  var _controller = ScrollController();
  var _allowReverse = true, _allowForward = true;
  var _prevOffset = 0.0;
  var _prevForwardOffset = -_containerHeight;
  var _prevReverseOffset = 0.0;

  @override
  void initState() {
    super.initState();
    _controller.addListener(_listener);
  }

  // entire logic is inside this listener for ListView
  void _listener() {
    double offset = _controller.offset;
    var direction = _controller.position.userScrollDirection;

    if (direction == ScrollDirection.reverse) {
      _allowForward = true;
      if (_allowReverse) {
        _allowReverse = false;
        _prevOffset = offset;
        _prevForwardOffset = _fromTop;
      }

      var difference = offset - _prevOffset;
      _fromTop = _prevForwardOffset + difference;
      if (_fromTop > 0) _fromTop = 0;
    } else if (direction == ScrollDirection.forward) {
      _allowReverse = true;
      if (_allowForward) {
        _allowForward = false;
        _prevOffset = offset;
        _prevReverseOffset = _fromTop;
      }

      var difference = offset - _prevOffset;
      _fromTop = _prevReverseOffset + difference;
      if (_fromTop < -_containerHeight) _fromTop = -_containerHeight;
    }
    setState(() {}); // for simplicity I'm calling setState here, you can put bool values to only call setState when there is a genuine change in _fromTop
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("ListView")),
      body: Stack(
        children: <Widget>[
          _yourListView(),
          Positioned(
            top: _fromTop,
            left: 0,
            right: 0,
            child: _yourContainer(),
          )
        ],
      ),
    );
  }

  Widget _yourListView() {
    return ListView.builder(
      itemCount: 100,
      controller: _controller,
      itemBuilder: (_, index) => ListTile(title: Text("Item $index")),
    );
  }

  Widget _yourContainer() {
    return Opacity(
      opacity: 1 - (-_fromTop / _containerHeight),
      child: Container(
        height: _containerHeight,
        color: Colors.red,
        alignment: Alignment.center,
        child: Text("Your Container", style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.white)),
      ),
    );
  }
}