How to programmatically change Z-Index of widget Stack in Flutter

3,754

Solution 1

try this:

class _FlipIndex extends State<FlipIndex> {
  List<Widget> _stackChildren = [];
  int currentIndex = 0;

  @override
  void initState() {
    super.initState();
    _stackChildren.add(_stackChild(Colors.yellow, 30));
    _stackChildren.add(_stackChild(Colors.green, -30));
  }

  //call this function for swapping items
  void _swapOrder() {
    Widget _first = _stackChildren[0];
    _stackChildren.removeAt(0);
    _stackChildren.add(_first);
    setState(() {});
  }

  Widget _stackChild(Color childColor, double xOffset) {
    return Transform.translate(
      key: UniqueKey(),
      offset: Offset(xOffset, 0.0),
      child: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
          color: childColor,
          shape: BoxShape.rectangle,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        onTap: () {
          _swapOrder();
        },
        child: Stack(
          alignment: Alignment.center,
          children: _stackChildren,
        ),
      ),
    );
  }
}

Solution 2

Try this package https://pub.dev/packages/indexed

Example image:

example image

This package allows you to order items inside the stack using index like z-index in CSS.

Easily you can change the order of items by change the index property

This is an example of how it works

Indexer(
    children: [
        Indexed(
          index: 100,
          child: Positioned(
            //...
          )
        ),
        Indexed(
          index: 1000,
          child: Positioned(
            //...
          )
        ),
        Indexed(
          index: 3,
          child: Positioned(
            //...
          )
        ),
    ],
);

if you are using bloc of some complex widget you can extands or implement the IndexedInterface class and override index getter:

class IndexedDemo extends IndexedInterface {
    int index = 5;
}

or implements

class IndexedDemo extends AnimatedWidget implements IndexedInterface {
    int index = 1000;
    //...

    //...
}

then use it just like Indexed class widget:

Indexer(
    children: [
        IndexedDemo(
          index: 100,
          child: Positioned(
            //...
          )
        ),
        IndexedFoo(
          index: 1000,
          child: Positioned(
            //...
          )
        ),
    ],
);

Online demo Video demo

Share:
3,754
Adam Kif
Author by

Adam Kif

Updated on December 30, 2022

Comments

  • Adam Kif
    Adam Kif over 1 year

    As you can see in this Stack the yellow cube is at the bellow of a purple cube.

    when I click, I want to change the index of the yellow cube to transform it from index 0 to 1 and the purple cube from index 1 to 0, vice versa.

    square

    I tried IndexedStack but it's only showing a single child from a list of children.

    class _FlipIndex extends State<FlipIndex> {
    
      int currentIndex = 0;
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: GestureDetector(
            onTap: (){
              // Change Z-Index of widget
            },
            child: Stack(
              alignment: Alignment.center,
              children: [
                Transform.translate(
                  offset: Offset(-30.0, 0.0),
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: Colors.yellow,
                      shape: BoxShape.rectangle,
                    ),
                  ),
                ),
                Transform.translate(
                  offset: Offset(30.0, 0.0),
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: Colors.purple,
                      shape: BoxShape.rectangle,
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    • pskink
      pskink almost 3 years
      you have to change the order of widgets in children: array - there is no other way
    • CrimsonFoot
      CrimsonFoot almost 3 years
      as @pskink said you have to resort the List of Widgets but if you give proper key value to each child it would be done more efficiently
    • Adam Kif
      Adam Kif almost 3 years
      I'm looking for something similar to Z-Index in CSS, without changing the order manually, but programmatically, and, half of the purple cube should also appear below the yellow cube.
    • pskink
      pskink almost 3 years
      "I'm looking for something similar to Z-Index in CSS," - there is no such thing
    • Adam Kif
      Adam Kif almost 3 years
      This is bad news, I appreciate your effort @pskink.
    • pskink
      pskink almost 3 years
      "This is bad news," - whats wrong with ordering children: list?
    • Adam Kif
      Adam Kif almost 3 years
      I'm working on animation, every time I want to flip between indexes in Stack, at the same time keep half of each cube. Do you see the problem?
    • pskink
      pskink almost 3 years
      most likely you should use CustomPaint then
    • Adam Kif
      Adam Kif almost 3 years
      The solution that I found, is to create twice for each cube, then toggle between the state of the opacity.
  • Adam Kif
    Adam Kif almost 3 years
    Your solution is the same as IndexedStack, it's only showing a single child. Thanks Jim
  • Jim
    Jim almost 3 years
    NONON, you need to change the offset of 2 children too~, i didn't implement it, you need to change it and try
  • Gilian
    Gilian over 2 years
    How change z-order without rebuild entire stack?