如何使类似堆栈的定位Widget可滚动?

时间:2018-08-27 03:03:13

标签: flutter flutter-layout flutter-animation flutter-positioned

我想创建一个UI组件,该组件将堆叠在屏幕其余部分的顶部,因此我可以在用户视图中转换它,但我也想使其可滚动。

Screen without the scrollable component

Scrollable component on top of the screen

我唯一想到的方法是使用Stack and Positioned小部件,但是不幸的是Stack中的组件无法滚动。

我正在考虑GestureDetector,并手动将列表向右滚动,这意味着将其中的很大一部分放在屏幕渲染区域之外。

您能想到一个更优雅的解决方案吗?

谢谢, 托马斯

1 个答案:

答案 0 :(得分:0)

import 'package:flutter/material.dart';

class SlidingDrawer extends StatelessWidget {
  final Widget drawer;
  final OpenableController openableController;

  SlidingDrawer({@required this.drawer, @required this.openableController});

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        GestureDetector(
          onTap: openableController.isOpen() ? openableController.close : null,
        ),
        FractionalTranslation(
          translation: Offset(1.0 - openableController.percentOpen, 0.0),
          child: Align(
            child: drawer,
            alignment: Alignment.centerRight,
          ),
        ),
      ],
    );
  }
}

class OpenableController extends ChangeNotifier {
  OpenedState _state;
  AnimationController openingController;

  OpenableController(
      {@required TickerProvider vsync, @required Duration openDuration})
      : openingController =
            AnimationController(vsync: vsync, duration: openDuration) {
    openingController
      ..addListener(notifyListeners)
      ..addStatusListener((status) {
        switch (status) {
          case AnimationStatus.forward:
            _state = OpenedState.opening;
            break;
          case AnimationStatus.reverse:
            _state = OpenedState.closing;
            break;
          case AnimationStatus.completed:
            _state = OpenedState.open;
            break;
          case AnimationStatus.dismissed:
            _state = OpenedState.closed;
            break;
        }

        notifyListeners();
      });
  }

  get state => _state;

  get percentOpen => openingController.value;

  bool isOpen() {
    return _state == OpenedState.open;
  }

  bool isOpening() {
    return _state == OpenedState.opening;
  }

  bool isClosed() {
    return _state == OpenedState.closed;
  }

  bool isClosing() {
    return _state == OpenedState.closing;
  }

  void open() {
    openingController.forward();
  }

  void close() {
    openingController.reverse();
  }

  void toggle() {
    if (isClosed()) {
      open();
    } else if (isOpen()) {
      close();
    }
  }
}

enum OpenedState { open, closed, opening, closing }

上面是一个通用组件,只需提供您想从右边抽屉的内容,然后将其放入堆栈中,

在您的主要

 OpenableController openableController;


  @override
  void initState() {
    super.initState();
    openableController = OpenableController(
        vsync: this, openDuration: Duration(milliseconds: 250))
      ..addListener(() => setState(() {}));
  }

然后打开

openableController.open