Search code examples
flutterflutter-animationbottom-sheet

Flutter: Bottom sheet animation behind a button


At the bottom of the screen is a button. When the button is pressed, a bottom sheet should slide up behind the button.

I'm failing to get the animation right. I tried using a stack.

In the following flutter code, the bottom sheet doesn't slide up from the bottom of the screen but from the upper side of the button. How can I fix it?

import 'package:flutter/material.dart';

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

  @override
  State<BottomSheetExample> createState() => _BottomSheetExampleState();
}

class _BottomSheetExampleState extends State<BottomSheetExample> {
  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      backgroundColor: Colors.green,
      bottomSheet: MyBottomSheet(),
      body: Center(child: Text('Body')),
    );
  }
}

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

  @override
  MyBottomSheetState createState() => MyBottomSheetState();
}

class MyBottomSheetState extends State<MyBottomSheet> {
  double _size = 100;
  bool _large = false;

  void _updateSize() {
    setState(() {
      _large = !_large;
      _size = _large ? 200 : 100;
    });
  }

  @override
  Widget build(BuildContext context) {
    return BottomSheet(
      onClosing: () {},
      builder: (BuildContext context) => Stack(
        children: [
          AnimatedSize(
            curve: Curves.elasticOut,
            duration: const Duration(milliseconds: 2000),
            child: Container(
              color: Colors.amber,
              height: _size,
              padding: const EdgeInsets.all(20),
              child: const Center(child: Text('Bottom Sheet')),
            ),
          ),
          Positioned(
            bottom: 10,
            child: ElevatedButton(
              onPressed: () => _updateSize(),
              child: const Text("Toggle"),
            ),
          ),
        ],
      ),
    );
  }
}


Solution

  • please try this one. Its easy to mess up with stack. I used here AnimatedContainer for the sake of simplicity, but normally you can use also AnimatedSize with no problem. If you have any questions, feel free to ask!

    class MyWidget extends StatefulWidget {
      const MyWidget({
        Key? key,
      }) : super(key: key);
    
      @override
      State<MyWidget> createState() => _MyWidgetState();
    }
    
    class _MyWidgetState extends State<MyWidget> {
      var _isExpanded;
      @override
      void initState() {
        super.initState();
        _isExpanded = false;
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          alignment: AlignmentDirectional.bottomStart,
          children: [
            Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Expanded(
                  child: Container(
                    color: Colors.red,
                  ),
                ),
                Expanded(
                  child: Container(
                    color: Colors.amber,
                  ),
                ),
                Expanded(
                  child: Container(
                    color: Colors.purple,
                  ),
                ),
              ],
            ),
            Stack(
              alignment: AlignmentDirectional.bottomCenter,
              children: [
                AnimatedContainer(
                  height: _isExpanded ? 100 : 0,
                  color: Colors.blue,
                  duration: const Duration(milliseconds: 500),
                ),
                TextButton(
                    onPressed: () {
                      setState(() {
                        _isExpanded = !_isExpanded;
                      });
                    },
                    style: TextButton.styleFrom(
                      backgroundColor: Colors.pink,
                    ),
                    child: const Text('Press me!')),
              ],
            ),
          ],
        );
      }
    }