Flutter - changing a Stack Order

4,994

Make a variable in your widget that keeps track of the children:

List<Widget> stackChildren = <Widget>[
          new Icon(Icons.monetization_on, key: GlobalKey(), size: 60.0, color: const 
Color.fromRGBO(200, 100, 180, 1.0)),
          new Positioned(
            left: 20.0,
            child: new Icon(Icons.monetization_on, key: GlobalKey(), size: 60.0, color: const 
Color.fromRGBO(000, 10, 130, 1.0)),
          ),
          new Positioned(
            left:40.0,
            child: new Icon(Icons.monetization_on, key: GlobalKey(), size: 60.0, color: const Color.fromRGBO(218, 165, 32, 1.0)),
          )

        ];

Then in whatever function you have to trigger the order switch, you can just call the following function:

void swapStackChildren() {
    final temp = stackChildren[0];
    setState(() {
          stackChildren[0] = stackChildren[2];
          stackChildren[2] = temp;
        });
  }

Edit: As suggested by the comments, it's a better idea just to assign a new value to stackChildren instead of modifying it. So you should instead do something like this:

void swapStackChildren() {
  setState(() {
    stackChildren = [
      new Positioned(
          left: 40.0,
          child: new Icon(Icons.monetization_on,
              key: GlobalKey(),
              size: 60.0,
              color: const Color.fromRGBO(218, 165, 32, 1.0))),
      new Icon(Icons.monetization_on,
          key: GlobalKey(),
          size: 60.0,
          color: const Color.fromRGBO(200, 100, 180, 1.0)),
      new Positioned(
        left: 20.0,
        child: new Icon(Icons.monetization_on,
            key: GlobalKey(),
            size: 60.0,
            color: const Color.fromRGBO(000, 10, 130, 1.0)),
      ),
    ];
  });
}

Edit:

Here is with the full sample code:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

AnimationController timerController;

void main() => runApp(MaterialApp(
      home: MyApp(),
    ));

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  AnimationController timerController;
  List<Widget> stackChildren = <Widget>[
      new Icon(Icons.monetization_on,
          key: GlobalKey(),
          size: 60.0,
          color: const Color.fromRGBO(50, 50, 50, 1.0)),
      new Positioned(
        left: 20.0,
        child: new Icon(Icons.monetization_on,
            key: GlobalKey(),
            size: 60.0,
            color: const Color.fromRGBO(50, 100, 150, 1.0)),
      ),
    ];

  void swapStackChildren() {
      setState(() {
        print("swapStackChildren");
        stackChildren = [
          new Positioned(
              left: 40.0,
              child: new Icon(Icons.monetization_on,
                  key: GlobalKey(),
                  size: 60.0,
                  color: const Color.fromRGBO(150, 00, 200, 1.0))),
          new Icon(Icons.monetization_on,
              key: GlobalKey(),
              size: 100.0,
              color: const Color.fromRGBO(200, 200, 100, 1.0)),
        ];
      });
    }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(8.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Stack(children: stackChildren),
            new RaisedButton(
              child: const Text('Swop'),
              color: Theme.of(context).accentColor,
              elevation: 4.0,
              splashColor: Colors.blueGrey,
              onPressed: () {
                swapStackChildren();
              },
            ),
          ],
        ),
      ),
    );
  }
}
Share:
4,994
Kevin Dev
Author by

Kevin Dev

Updated on December 07, 2022

Comments

  • Kevin Dev
    Kevin Dev over 1 year

    I have a Stack where on a condition (e.g. user click), I want one of the lower order widgets to be pushed to the top of the stack. Using the code below as a simple example - what code do I need in a setState() method to reorder so that the first (bottom) widget becomes the last (top) widget?

    new Stack(
            children: <Widget>[
              new Icon(Icons.monetization_on, key: GlobalKey(), size: 60.0, color: const 
    Color.fromRGBO(200, 100, 180, 1.0)),
              new Positioned(
                left: 20.0,
                child: new Icon(Icons.monetization_on, key: GlobalKey(), size: 60.0, color: const 
    Color.fromRGBO(000, 10, 130, 1.0)),
              ),
              new Positioned(
                left:40.0,
                child: new Icon(Icons.monetization_on, key: GlobalKey(), size: 60.0, color: const Color.fromRGBO(218, 165, 32, 1.0)),
              )
    
            ],
          );
    

    I have edited the proposed solution and the stack does not change order. Here is the sample code in full (the print statement print to the console as expected on button press):

    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    
    AnimationController timerController;
    
    void main() => runApp(MaterialApp(
      home: MyApp(),
    ));
    
    class MyApp extends StatefulWidget {
     @override
       MyAppState createState() => MyAppState();
    }
    
    class MyAppState extends State<MyApp> {
      AnimationController timerController;
    
      @override
      Widget build(BuildContext context) {
    List<Widget> stackChildren = <Widget>[
      new Icon(Icons.monetization_on,
          key: GlobalKey(),
          size: 60.0,
          color: const Color.fromRGBO(50, 50, 50, 1.0)),
      new Positioned(
        left: 20.0,
        child: new Icon(Icons.monetization_on,
            key: GlobalKey(),
            size: 60.0,
            color: const Color.fromRGBO(50, 100, 150, 1.0)),
      ),
    ];
    
    void swapStackChildren() {
         setState(() {
           print("swapStackChildren");
        stackChildren = [
          new Positioned(
              left: 40.0,
              child: new Icon(Icons.monetization_on,
                  key: GlobalKey(),
                  size: 60.0,
                  color: const Color.fromRGBO(150, 00, 200, 1.0))),
          new Icon(Icons.monetization_on,
              key: GlobalKey(),
              size: 100.0,
              color: const Color.fromRGBO(200, 200, 100, 1.0)),
        ];
      });
    }
    
    return Scaffold(
      body: Padding(
        padding: EdgeInsets.all(8.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Stack(children: stackChildren),
            new RaisedButton(
              child: const Text('Swop'),
              color: Theme.of(context).accentColor,
              elevation: 4.0,
              splashColor: Colors.blueGrey,
              onPressed: () {
                swapStackChildren();
              },
            ),
          ],
        ),
      ),
    );
    }
    

    }

  • Rémi Rousselet
    Rémi Rousselet over 5 years
    Don't edit the list content. Replace it with a new one instead
  • Ringil
    Ringil over 5 years
    @RémiRousselet Do you mean for swapStackChildren or do you mean using a StatelessWidget instead? Because for the former, I don't see a huge difference between the proposed implementation and something like setState(() => stackChildren = newStackChildrenOrder);
  • Rémi Rousselet
    Rémi Rousselet over 5 years
    Flutter uses immutability. You should not mutate object. The same code but using ListView instead of Stack would have a bug due to this for example
  • Ringil
    Ringil over 5 years
    @KevinDev did you call swapStackChildren somewhere?
  • Kevin Dev
    Kevin Dev over 5 years
    Yes - there is a raised button widget in the scaffold and I call the swop function in the onPressed.
  • Ringil
    Ringil over 5 years
    @KevinDev See my second edit. It will correctly swap the stackChildren.
  • Kevin Dev
    Kevin Dev over 5 years
    Perfect! Thank you @Ringil
  • Ringil
    Ringil over 5 years
    @KevinDev If you found this answer useful, please accept it. Thanks :)
  • Kevin Dev
    Kevin Dev over 5 years
    I upvoted yesterday, but didn't see the greyed out tick. Now accepted. Thank you.
  • Kevin Dev
    Kevin Dev over 5 years
    I have an implementation query that I will post as a separate query.