如何在 Flutter 中偏移脚手架小部件?

How can I offset a scaffold widget in Flutter?

我想设计一个如下所示的自定义导航window。

我计划:

  1. 创建我的导航小部件
  2. 创建我的新闻提要小部件
  3. 堆叠两个小部件(新闻提要在导航顶部)
  4. 如果单击菜单图标,将新闻源小部件转换为某个值,以便下方的导航小部件可见

我做了前三步。我对第四个有问题。我设置了一个 Offset 状态变量,并将脚手架小部件放置在 Positioned 小部件中。我将 Positioned class 的 'left' 设置为 Offset.dx.

代码:


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

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

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
            title: 'Flutter Demo',
            theme: new ThemeData(
                primarySwatch: const MaterialColor(0xfff06000, const {
                   50: const Color(0xfffff0e6),
                  100: const Color(0xffffd1b3),
                  200: const Color(0xffffb380),
                  300: const Color(0xffff944d),
                  400: const Color(0xffff751a),
                  500: const Color(0xfff06000),
                  600: const Color(0xffcc5200),
                  700: const Color(0xffb34700),
                  800: const Color(0xff993d00),
                  900: const Color(0xff662900),
                })),
            //I stack the classes
            home: new Stack(
              children: [
                new MyNavPage(),
                new MyHomePage(title: "Home",initialOffset: new Offset(0.0, 0.0),),
              ],
            )
        );
      }
    }

    // This is my news feed class

    class MyHomePage extends StatefulWidget {

      final String title;
      final Offset initialOffset;

      MyHomePage({Key key, this.title, this.initialOffset}) : super(key: key);

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

    class _MyHomePageState extends State with TickerProviderStateMixin {

      Offset position = new Offset(0.0, 0.0);

      int _counter = 0;

      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }

      void initState() {
        super.initState();
        position = widget.initialOffset;
      }

      @override
      Widget build(BuildContext context) {

        final scaffold = new Scaffold(
          primary: true,
          appBar: new AppBar(
            title: new Text(widget.title),
            centerTitle: true,
            leading: new IconButton(icon: new Icon(Icons.menu),onPressed: () => setState(() => position = new Offset(100.0, 0.0)),),
          ),
          backgroundColor: Colors.white30,
          body: new Container(
            child: new Center(
              child: new Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  new Text(
                    'You have pushed the button this many times:',
                  ),
                  new Text(
                    '$_counter',
                    style: Theme
                        .of(context)
                        .textTheme
                        .display1,
                  ),
                ],
              ),
            ),
          ),
          floatingActionButton: new FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: new Icon(Icons.add),
          ),
        );

        return new Positioned(
          left: position.dx,
          child:scaffold,
        );
      }

    }

    // My navigation class. It has those navigation options as a column to the left.
    // The width is 100.0, hence I offset my home page by 100.0


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

      @override
      _MyNavPageState createState() => new _MyNavPageState();
    }

    class _MyNavPageState extends State {

      @override
      Widget build(BuildContext context) {
        Expanded createNavChild(Icon i, Text t) {
          return new Expanded(
            child: new GestureDetector(
              child: new Container(
                width: 100.0,
                decoration: new BoxDecoration(color: Colors.red,),
                child: new Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    i,
                    t
                  ],
                ),
              ),
            ),
          );
        }

        return new Scaffold(
          primary: true,
          body: new Container(
            margin: MediaQuery
                .of(context)
                .padding,
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                createNavChild(new Icon(Icons.home, size: 30.0), new Text("Home")),
                createNavChild(
                    new Icon(Icons.person_add, size: 30.0), new Text("Register")),
                createNavChild(
                    new Icon(Icons.search, size: 30.0), new Text("Player Search")),
                createNavChild(
                    new Icon(Icons.event, size: 30.0), new Text("Events")),
                createNavChild(new Icon(Icons.file_download, size: 30.0),
                    new Text("Downloads")),
                createNavChild(
                    new Icon(Icons.call, size: 30.0), new Text("Contact")),
              ],
            ),
            decoration: new BoxDecoration(color: Colors.transparent,),
          ),
        );
      }
    }

抛出错误:

I/flutter ( 3090): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 3090): The following assertion was thrown during performLayout():
I/flutter ( 3090): RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
I/flutter ( 3090): This probably means that it is a render object that tries to be as big as possible, but it was put
I/flutter ( 3090): inside another render object that allows its children to pick their own size.
I/flutter ( 3090): The nearest ancestor providing an unbounded width constraint is:
I/flutter ( 3090):   RenderStack#df1fd NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):   creator: Stack ← Semantics ← Builder ← RepaintBoundary-[GlobalKey#274fe] ← IgnorePointer ←
I/flutter ( 3090):   FadeTransition ← FractionalTranslation ← SlideTransition ← _MountainViewPageTransition ←
I/flutter ( 3090):   AnimatedBuilder ← RepaintBoundary ← _FocusScopeMarker ← ⋯
I/flutter ( 3090):   parentData:  (can use size)
I/flutter ( 3090):   constraints: BoxConstraints(w=360.0, h=640.0)
I/flutter ( 3090):   size: Size(360.0, 640.0)
I/flutter ( 3090):   alignment: AlignmentDirectional.topStart
I/flutter ( 3090):   textDirection: ltr
I/flutter ( 3090):   fit: loose
I/flutter ( 3090):   overflow: clip
I/flutter ( 3090): The nearest ancestor providing an unbounded height constraint is:
I/flutter ( 3090):   RenderStack#df1fd NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):   creator: Stack ← Semantics ← Builder ← RepaintBoundary-[GlobalKey#274fe] ← IgnorePointer ←
I/flutter ( 3090):   FadeTransition ← FractionalTranslation ← SlideTransition ← _MountainViewPageTransition ←
I/flutter ( 3090):   AnimatedBuilder ← RepaintBoundary ← _FocusScopeMarker ← ⋯
I/flutter ( 3090):   parentData:  (can use size)
I/flutter ( 3090):   constraints: BoxConstraints(w=360.0, h=640.0)
I/flutter ( 3090):   size: Size(360.0, 640.0)
I/flutter ( 3090):   alignment: AlignmentDirectional.topStart
I/flutter ( 3090):   textDirection: ltr
I/flutter ( 3090):   fit: loose
I/flutter ( 3090):   overflow: clip
I/flutter ( 3090): The constraints that applied to the RenderCustomMultiChildLayoutBox were:
I/flutter ( 3090):   BoxConstraints(unconstrained)
I/flutter ( 3090): The exact size it was given was:
I/flutter ( 3090):   Size(Infinity, Infinity)
I/flutter ( 3090): See https://flutter.io/layout/ for more information.
I/flutter ( 3090): When the exception was thrown, this was the stack:
I/flutter ( 3090): #0      RenderBox.debugAssertDoesMeetConstraints. (package:flutter/src/rendering/box.dart:1698:9)
I/flutter ( 3090): #1      RenderBox.debugAssertDoesMeetConstraints (package:flutter/src/rendering/box.dart:1772:6)
I/flutter ( 3090): #2      RenderBox.size=. (package:flutter/src/rendering/box.dart:1507:17)
I/flutter ( 3090): #3      RenderBox.size= (package:flutter/src/rendering/box.dart:1507:65)
I/flutter ( 3090): #4      RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:354:5)
I/flutter ( 3090): #5      RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #6      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #7      RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #8      _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #9      _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1141:11)
I/flutter ( 3090): #10     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #11     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:553:15)
I/flutter ( 3090): #12     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #13     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #14     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #15     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #16     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #17     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #18     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #19     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #20     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #21     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #22     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #23     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #24     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #25     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #26     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #27     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #28     RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:2712:13)
I/flutter ( 3090): #29     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #30     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:514:15)
I/flutter ( 3090): #31     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #32     __RenderTheatre&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #33     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #34     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #35     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #36     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #37     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #38     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #39     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #40     _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:107:13)
I/flutter ( 3090): #41     RenderObject.layout (package:flutter/src/rendering/object.dart:1570:7)
I/flutter ( 3090): #42     RenderView.performLayout (package:flutter/src/rendering/view.dart:125:13)
I/flutter ( 3090): #43     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1445:7)
I/flutter ( 3090): #44     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:709:18)
I/flutter ( 3090): #45     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:270:19)
I/flutter ( 3090): #46     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:627:13)
I/flutter ( 3090): #47     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:208:5)
I/flutter ( 3090): #48     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter ( 3090): #49     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter ( 3090): #50     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.scheduleWarmUpFrame. (package:flutter/src/scheduler/binding.dart:751:7)
I/flutter ( 3090): #52     _Timer._runTimers (dart:isolate/runtime/libtimer_impl.dart:382:19)
I/flutter ( 3090): #53     _Timer._handleMessage (dart:isolate/runtime/libtimer_impl.dart:416:5)
I/flutter ( 3090): #54     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:165:12)
I/flutter ( 3090): (elided one frame from package dart:async)
I/flutter ( 3090): The following RenderObject was being processed when the exception was fired:
I/flutter ( 3090):   RenderCustomMultiChildLayoutBox#04aef relayoutBoundary=up3 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):   creator: CustomMultiChildLayout ← AnimatedBuilder ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
I/flutter ( 3090):   _InkFeatures-[GlobalKey#64807 ink renderer] ← NotificationListener ←
I/flutter ( 3090):   PhysicalModel ← AnimatedPhysicalModel ← Material ← PrimaryScrollController ← _ScaffoldScope ←
I/flutter ( 3090):   Scaffold ← ⋯
I/flutter ( 3090):   parentData:  (can use size)
I/flutter ( 3090):   constraints: BoxConstraints(unconstrained)
I/flutter ( 3090):   size: Size(Infinity, Infinity)
I/flutter ( 3090): This RenderObject had the following descendants (showing up to depth 5):
I/flutter ( 3090):   RenderPositionedBox#4ac32 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):     RenderFlex#a08f4 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):       RenderParagraph#eba89 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):       RenderParagraph#5afd6 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):   RenderConstrainedBox#0b71f NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):     RenderPhysicalModel#fa853 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):       _RenderInkFeatures#45d75 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):         RenderPositionedBox#7bd87 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):           RenderPadding#3faff NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):   RenderStack#4eccb NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):     RenderTransform#16934 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):       RenderTransform#317f7 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):         RenderSemanticsAnnotations#f02cf NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090):           RenderConstrainedBox#75c14 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 3090): ════════════════════════════════════════════════════════════════════════════════════════════════════

问题:

  1. 我的方法正确吗?
  2. 如果正确,错误告诉我什么?
  3. 如果这不是正确的方法,是否有更简单或更好的方法来实现?

如果我对此有误,请告诉我,但听起来您希望导航抽屉在用户单击菜单按钮时打开。值得庆幸的是,Flutter 已经处理了这个问题!

您可以简单地使用脚手架的 drawer 属性。您将一个抽屉(或可能是另一个小部件)传递给它来显示,它会自动处理以使其可从左侧滑入。

如果您还想在按下按钮时打开它,您可以使用按钮中的 Scaffold.of(context).openDrawer();。请注意,要获取包含脚手架的上下文,您必须使用 Builder 或使您的应用栏成为新的小部件。

经过一番研究,我在 YouTube 上找到了这个精彩的视频。它非常有用,完全解决了我的问题。

他使用了相同的方法,但代码要好得多。我会推荐任何正在学习 Flutter 的人观看他的所有视频。

Link 到视频 here

包隐藏抽屉菜单

这些包使用起来非常简单。 Link 到包是 here