Search code examples
flutterflutter-listview

Does FadeTransistion and IndexedStack affect listview in flutter?


i am a newbie in flutter, i use FadeTransistion, indexedStack and bottomNavigationBar to navigate tabs in my scaffold, but the it doesn't seem to affect my listview on 'page2', the list view become the background of 'page3' and 'page1' ( i set long duration for the fade and see it), how to make the listview disappear when i go to others tab?

Widget 'FadeIndexedStack' i reference from https://gist.github.com/diegoveloper/1cd23e79a31d0c18a67424f0cbdfd7ad, thank to the author

here is my code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My app',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;
  List<BottomNavigationBarItem> items = [
    BottomNavigationBarItem(icon: Icon(Icons.pages), label: 'page 1'),
    BottomNavigationBarItem(icon: Icon(Icons.pages), label: 'page 2'),
    BottomNavigationBarItem(icon: Icon(Icons.pages), label: 'page 3'),
  ];
  @override
  Widget build(BuildContext context) {
    ColorScheme theme = Theme.of(context).colorScheme;
    return Scaffold(
      body: FadeIndexedStack(
        index: _currentIndex,
        children: [
          page1(),
          page2(),
          page3(),
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        items: items,
        backgroundColor: theme.primary,
        selectedItemColor: theme.onPrimary,
        showUnselectedLabels: false,
        showSelectedLabels: true,
        unselectedItemColor: theme.onPrimary.withOpacity(0.5),
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
      ),
    );
  }
}

class page1 extends StatelessWidget {
  const page1({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.amber,
      child: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
          alignment: Alignment.center,
          child: Text('page 1'),
        ),
      ),
    );
  }
}

class page2 extends StatelessWidget {
  const page2({super.key});
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        ListTile(
          tileColor: Colors.blueAccent,
          title: Text('page 2.1'),
          shape: Border.symmetric(
            horizontal: BorderSide(
              color: Colors.black,
              width: 1.0,
              style: BorderStyle.solid,
            ),
          ),
        ),
        ListTile(
          tileColor: Colors.blueAccent,
          title: Text('page 2.2'),
          shape: Border.symmetric(
            horizontal: BorderSide(
              color: Colors.black,
              width: 1.0,
              style: BorderStyle.solid,
            ),
          ),
        ),
        ListTile(
          tileColor: Colors.blueAccent,
          title: Text('page 2.3'),
          shape: Border.symmetric(
            horizontal: BorderSide(
              color: Colors.black,
              width: 1.0,
              style: BorderStyle.solid,
            ),
          ),
        ),
      ],
    );
  }
}

class page3 extends StatelessWidget {
  const page3({super.key});

  @override
  Widget build(BuildContext context) {
    return Text(
      'page 3',
      style: TextStyle(fontSize: 30, color: Colors.red),
    );
  }
}

class FadeIndexedStack extends StatefulWidget {
  int index;
  List<Widget> children;
  Duration duration;
  FadeIndexedStack({
    Key? key,
    required this.index,
    required this.children,
    this.duration = const Duration(milliseconds: 3000),
  });

  @override
  State<FadeIndexedStack> createState() => _FadeIndexedStackState();
}

class _FadeIndexedStackState extends State<FadeIndexedStack>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: widget.duration);
    _controller.forward(from: 0.0);
  }

  @override
  void didUpdateWidget(FadeIndexedStack old) {
    super.didUpdateWidget(old);
    if (widget.index != old.index) {
      _controller.forward(from: 0.0);
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _controller,
      child: IndexedStack(
        index: widget.index,
        children: widget.children,
      ),
    );
  }
}

debug video: bug.gif


Solution

  • That's because the Stack and IndexedStack work in that way, all your widgets are rendered but one is on top of the other, you can uso Positioned.fill on each of the children of your IndexedStack, like this:

    FadeIndexedStack(
            index: _currentIndex,
            children: [
              Positioned.fill(child: page1()),
              Positioned.fill(child: page2()),
              Positioned.fill(child: page3()),
            ],
          ),