Simple slide up widget animation

Step 1: Static UI

home_screen.dart

class HomeScreenBody extends StatelessWidget {
  SlideUpController slideUpController = SlideUpController();

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.bottomCenter,
      children: [
        Container(
          child: Column(
            children: [
              RaisedButton(
                child: Text('Slide up widget'),
                onPressed: () {
                  
                },
              )
            ],
          ),
        ),
        SlideUpWidget()
      ],
    );
  }
}

slideup_widget.dart

import 'package:flutter/material.dart';

class SlideUpWidget extends StatefulWidget {
  final SlideUpController controller;

  const SlideUpWidget({Key key, this.controller}) : super(key: key);

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

class _SlideUpWidgetState extends State<SlideUpWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 200,
      decoration: BoxDecoration(
          color: Colors.red,
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(20),
              topRight: Radius.circular(20))),
    );
  }
}

Step 2: Add action

I use Flutter provider (https://pub.dev/packages/provider) to handle the action.

slideup_widget.dart

import 'package:provider/provider.dart';
class SlideUpProvider with ChangeNotifier {
  bool isShow = false;

  void updateState(bool newState) {
    isShow = newState;
    notifyListeners();
  }
}

I create a new simple controller to control the widget.

class SlideUpController {
  SlideUpController._private();

  static final SlideUpController instance = SlideUpController._private();

  factory SlideUpController() => instance;

  BuildContext _providerContext;

  set providerContext(BuildContext context) {
    if (_providerContext != context) {
      _providerContext = context;
    }
  }

  void toggle() {
    if (_providerContext != null) {
      final provider = _providerContext.read<SlideUpProvider>();
      provider.updateState(!provider.isShow);
    } else {
      print('Need init provider context');
    }
  }
}

the _SlideUpWidgetState updated

class _SlideUpWidgetState extends State<SlideUpWidget> {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => SlideUpProvider(),
      child: Consumer<SlideUpProvider>(
        builder: (context, provider, child) {
          widget.controller?.providerContext = context;
          return provider.isShow
              ? Container(
                  height: 200,
                  decoration: BoxDecoration(
                      color: Colors.red,
                      borderRadius: BorderRadius.only(
                          topLeft: Radius.circular(20),
                          topRight: Radius.circular(20))),
                )
              : Container();
        },
      ),
    );
  }
}

Add controller to home screen and trigger by button

class HomeScreenBody extends StatelessWidget {
  SlideUpController slideUpController = SlideUpController();

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.bottomCenter,
      children: [
        Container(
          child: Column(
            children: [
              RaisedButton(
                child: Text('Slide up widget'),
                onPressed: () {
                  slideUpController.toggle();
                },
              )
            ],
          ),
        ),
        SlideUpWidget(
          controller: slideUpController,
        )
      ],
    );
  }
}

Step 3: Add slide animation

The scenario: 

  • Opacity for main ui
  • Slide for SlideUpWidget

Update home_screen.dart

class HomeScreenBody extends StatefulWidget {
  @override
  _HomeScreenBodyState createState() => _HomeScreenBodyState();
}

class _HomeScreenBodyState extends State<HomeScreenBody>
    with SingleTickerProviderStateMixin {
  SlideUpController slideUpController = SlideUpController();

  AnimationController _controller;
  Animation<Offset> _offsetAnimation;
  Animation<double> _fadeAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 350),
      vsync: this,
    );
    _offsetAnimation = Tween<Offset>(
      begin: const Offset(0, 1),
      end: Offset.zero,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.decelerate,
    ))
      ..addStatusListener((status) {
        if (status == AnimationStatus.forward) {
          // Start animation at begin
          slideUpController.toggle();
        } else if (status == AnimationStatus.dismissed) {
          // To hide widget, we need complete animation first
          slideUpController.toggle();
        }
      });
    _fadeAnimation = Tween<double>(
      begin: 1,
      end: 0,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.decelerate,
    ));
  }

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

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.bottomCenter,
      children: [
        FadeTransition(
          opacity: _fadeAnimation,
          child: Container(
            height: double.infinity,
            width: double.infinity,
            color: Colors.grey,
            child: RaisedButton(
              child: Text('Slide up widget'),
              onPressed: () {
                if (_controller.isDismissed) {
                  _controller.forward();
                } else {
                  _controller.reverse();
                }
              },
            ),
          ),
        ),
        SlideTransition(
          position: _offsetAnimation,
          child: SlideUpWidget(
            controller: slideUpController,
          ),
        )
      ],
    );
  }
}

https://medium.com/p/56b14e0189c5

https://www.upwork.com/fl/nhancv

Liked it? Take a second to support nhancv on Patreon!

Leave a Reply

Your email address will not be published.Required fields are marked *