Create Custom Widget in Flutter - Download Indicator

In this post we will learn how to create Custom Widget in Flutter. As we all knows that Flutter is Cross Plaform development framework. So this Custom Widget will works for both Android and IOS.

 

This Custom widget will show the downloading status of the application with loading indicator.

Let's Start Now

First create a dart file inside lib folder with animate_button.dart name

 

Inside this we will create Custom widget called  ButtonAnimation widget.

 

In this Custom widget we used Animation Controller for add Animation to the widget.

AnimationController _scaleAnimationController;

_scaleAnimationController = AnimationController(
    vsync: this,
    duration: Duration(milliseconds: 300)
);

 

Here we passed vsync:this, to pass current state we need to extend our widget class with TickerProviderStateMixin

We applying Scale Animation to the widget by creating the Animation object like below

 

_scaleAnimation = Tween<double>(
  begin: 1.0,
  end: 1.05,
).animate(_scaleAnimationController)..addStatusListener((status) {
  if (status == AnimationStatus.completed) {
  
  }
});

 

The class will contains below code

import 'package:flutter/material.dart';

class ButtonAnimation extends StatefulWidget {
  final Color primaryColor;
  final Color darkPrimaryColor;
  double buttonWidth;
  double buttonHeight;

  ButtonAnimation(this.primaryColor, this.darkPrimaryColor,this.buttonWidth,this.buttonHeight);

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

class _ButtonAnimationState extends State<ButtonAnimation> with TickerProviderStateMixin {

  AnimationController _animationController;
  AnimationController _scaleAnimationController;

  Animation<double> _animation;
  Animation<double> _scaleAnimation;

  double buttonWidth = 200.0;
  double scale = 1.0;
  bool animationComplete = false;
  double barColorOpacity = .6;
  bool animationStart = false;


  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    _animationController = AnimationController(
        vsync: this,
        duration: Duration(seconds: 3)
    );

    _scaleAnimationController = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 300)
    );



    _scaleAnimationController = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 300)
    );


    _scaleAnimation = Tween<double>(
      begin: 1.0,
      end: 1.05,
    ).animate(_scaleAnimationController)..addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _scaleAnimationController.reverse();

        _animationController.forward();
      }
    });

    _animation = Tween<double>(
        begin: 0.0,
        end: buttonWidth
    ).animate(_animationController)..addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        setState(() {
          animationComplete = true;
          animationStart=false;
          barColorOpacity = .0;
        });
      }
    });
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();

    _animationController.dispose();

    _scaleAnimationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        AnimatedBuilder(
            animation: _scaleAnimationController,
            builder: (context, child) => Transform.scale(
              scale: _scaleAnimation.value,
              child: InkWell(
                onTap: () {
                  _scaleAnimationController.forward();
                  setState(() {
                    animationStart=true;
                  });
                },
                child: Container(
                  width: widget.buttonWidth,
                  height: widget.buttonHeight,
                  decoration: BoxDecoration(
                      color: widget.primaryColor,
                      borderRadius: BorderRadius.circular(3)
                  ),
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: Align(
                            child:
                            animationComplete == false ?
                            Text( (animationStart)?"Downloading...":"Download", style: TextStyle(color: Colors.white, fontSize: 16),)
                                :
                            Icon(Icons.check, color: Colors.white,)
                        ),
                      ),

                    ],
                  ),
                ),
              ),
            )
        ),
        Positioned(
            right: 10,
            top: 10,
            height: 30,
            width: 30,
            child:  (animationStart)?Center(
              child: CircularProgressIndicator(
              backgroundColor: Colors.white,
             valueColor: AlwaysStoppedAnimation<Color>(Colors.red),
              strokeWidth: 5,),
            ):Center(),
    ),



      ],
    );
  }
}

 

 

Now Create a main.dart file with below code

void main() {
  runApp(MaterialApp(home: CustomButton()));
}

class CustomButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ButtonAnimation(Color.fromRGBO(57, 92, 249, 1), Color.fromRGBO(44, 78, 233, 1),200,50),
              SizedBox(height: 20,),
              ButtonAnimation(Colors.yellow[700], Colors.yellow[800],200,50),
              SizedBox(height: 20,),

              ButtonAnimation(Colors.green[400], Colors.green[600],200,50),
              SizedBox(height: 20,),

              ButtonAnimation(Colors.red[700], Colors.red[800],200,50),

            ],
          ),
        ),
      ),
    );
  }
}

 

The Out put will be like below

Custom Button with Loading Indicator

 

 

Other Flutter Examples