Ad

How Can I Offset A Scaffold Widget In Flutter?

I want to design a custom navigation window like the one below.

Enter image description here

I planned to:

  1. Create my navigation widget
  2. Create my news feed widget
  3. Stack both widgets (news feed on top of the navigation)
  4. If the menu icon is clicked, translate the news feed widget to some value so that the underneath nav widget is visible

I did the first three steps. I have problems with the fourth one. I set an Offset state variable and placed my scaffold widget within a Positioned widget. I set the 'left' of the Positioned class to Offset.dx.

Code:

    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,),
          ),
        );
      }
    }

An error is thrown:

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): ════════════════════════════════════════════════════════════════════════════════════════════════════

Questions:

  1. Is my approach correct?
  2. If it is correct, what is the error telling me?
  3. If it is not the right approach, is there a simpler or better way to achieve this?
Ad

Answer

So after some research, I found this wonderful video on YouTube. It is very informative and exactly solves my problem.

He has used the same approach, but with much better code. I would recommend anyone who is learning Flutter to watch all his videos.

Link to video here.

Ad
source: stackoverflow.com
Ad