1

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

没有可滚动组件的屏幕

屏幕顶部的可滚动组件

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

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

你能想出一个更优雅的解决方案吗?

谢谢,托马斯

4

1 回答 1

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
于 2018-08-27T05:38:00.820 回答