【问题标题】:How to have the drawer push the content instead of going on top of it?如何让抽屉推动内容而不是放在上面?
【发布时间】:2021-06-11 19:37:24
【问题描述】:

我正在尝试构建类似于 slack 应用程序(见下面的屏幕截图)的东西,其中导航抽屉将屏幕推开而不是放在顶部。

我一直在尝试使用 Drawer 组件,但没有成功。我也看过PageView,但似乎孩子们需要占用 100% 的宽度。

有人知道如何实现它吗?

【问题讨论】:

  • scaffolds openDrawer 使用导航器,您可以使用带有Scrollable.ensureVisible(context) 的单子水平滚动视图(禁用滚动物理)来显示菜单

标签: flutter material-design


【解决方案1】:

编辑

使用StackAnimatedPositioned 可以获得类似的结果

class SlidingDrawer extends StatefulWidget {
  final Widget drawer;
  final Widget child;
  final int swipeSensitivity;
  final double drawerRatio;
  final Color overlayColor;
  final double overlayOpacity;
  final int animationDuration;
  final Curve animationCurve;

  SlidingDrawer({
    Key key,
    @required this.drawer,
    @required this.child,
    this.swipeSensitivity = 25,
    this.drawerRatio = 0.8,
    this.overlayColor = Colors.black,
    this.overlayOpacity = 0.5,
    this.animationDuration = 500,
    this.animationCurve = Curves.ease,
  }) : super(key: key);
  @override
  _SlidingDrawerState createState() => _SlidingDrawerState();
}

class _SlidingDrawerState extends State<SlidingDrawer> {
  bool _opened = false;

  void open() {
    setState(() {
      _opened = true;
    });
  }

  void close() {
    setState(() {
      _opened = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    final height = MediaQuery.of(context).size.height;
    final drawerWidth = width * widget.drawerRatio;

    return GestureDetector(
      onHorizontalDragUpdate: (details) {
        if (details.delta.dx > widget.swipeSensitivity) {
          open();
        } else if (details.delta.dx < -widget.swipeSensitivity) {
          close();
        }
      },
      child: SizedBox(
        width: width,
        height: height,
        child: Stack(
          children: [
            AnimatedPositioned(
              width: drawerWidth,
              height: height,
              left: _opened ? 0 : -drawerWidth,
              duration: Duration(milliseconds: widget.animationDuration),
              curve: widget.animationCurve,
              child: Container(
                color: Colors.amber,
                child: widget.drawer,
              ),
            ),
            AnimatedPositioned(
              height: height,
              width: width,
              left: _opened ? drawerWidth : 0,
              duration: Duration(milliseconds: widget.animationDuration),
              curve: widget.animationCurve,
              child: Stack(
                fit: StackFit.expand,
                children: [
                  widget.child,
                  AnimatedSwitcher(
                    duration: Duration(milliseconds: widget.animationDuration),
                    switchInCurve: widget.animationCurve,
                    switchOutCurve: widget.animationCurve,
                    child: _opened
                        ? GestureDetector(
                            onTap: () {
                              setState(() {
                                _opened = false;
                              });
                            },
                            child: Container(
                              color: widget.overlayColor.withOpacity(
                                widget.overlayOpacity,
                              ),
                            ),
                          )
                        : null,
                  )
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

原始答案

正如@Yadu 在评论中指出的那样

您可以使用带有 Scrollable.ensureVisible(context) 的单子水平滚动视图(禁用滚动物理)来显示菜单

使用水平滚动视图是有效的。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _drawerOpened = false;

  final drawerKey = new GlobalKey();
  final mainKey = new GlobalKey();

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      physics: NeverScrollableScrollPhysics(),
      scrollDirection: Axis.horizontal,
      child: Row(
        children: [
          Container(
            key: drawerKey,
            color: Colors.green,
            width: MediaQuery.of(context).size.width * 0.8,
          ),
          SizedBox(
            key: mainKey,
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: Scaffold(
              appBar: AppBar(
                title: Text("My Page"),
                leading: IconButton(
                  icon: Icon(Icons.menu),
                  onPressed: _toggleDrawer,
                ),
              ),
              body: Container(
                color: Colors.yellow,
                width: MediaQuery.of(context).size.width,
              ),
            ),
          ),
        ],
      ),
    );
  }

  void _toggleDrawer() {
    setState(() {
      _drawerOpened = !_drawerOpened;
    });
    if (_drawerOpened) {
      Scrollable.ensureVisible(drawerKey.currentContext);
    } else {
      Scrollable.ensureVisible(mainKey.currentContext);
    }
  }
}

【讨论】:

    猜你喜欢
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多