import 'dart:async'; import 'dart:math' as math; import 'package:flutter/material.dart'; class ButtonToProgress extends StatefulWidget { final double height; final double progressHeight; final String loadingText; final Duration duration; final TextStyle loadingTextStyle; final VoidCallback onPressed; final Stream onLoading; final Widget child; const ButtonToProgress({ Key key, this.height = 40.0, this.progressHeight = 5.0, this.loadingText, this.duration = const Duration(milliseconds: 300), this.loadingTextStyle, this.onPressed, this.onLoading, @required this.child, }) : assert(child != null), assert(height != null && height > 0), assert(progressHeight != null && progressHeight > 0 && progressHeight <= height), super(key: key); @override _ButtonToProgressState createState() => _ButtonToProgressState(); } class _ButtonToProgressState extends State { double _height; double _opacity = 0; bool _isLoading = false; StreamSubscription _subscription; @override void initState() { super.initState(); _height = widget.height; if (widget.onLoading != null) { _subscription = widget.onLoading.listen((bool isLoading) { setState(() { _isLoading = isLoading; _height = isLoading ? widget.progressHeight : widget.height; _opacity = isLoading ? 1 : 0; }); }); } } @override void dispose() { if (_subscription != null) { _subscription.cancel(); } super.dispose(); } @override Widget build(BuildContext context) { return Container( height: widget.height, child: Stack( children: [ if (widget.loadingText == null) Container() else Padding( padding: EdgeInsets.only(bottom: widget.progressHeight), child: AnimatedOpacity( child: Center( child: FittedBox( child: Text( widget.loadingText, style: widget.loadingTextStyle, ), ), ), opacity: _opacity, duration: Duration(milliseconds: widget.duration.inMilliseconds + 200), curve: Curves.easeInCubic, ), ), AnimatedPadding( duration: widget.duration, padding: EdgeInsets.only( top: math.max(widget.height - _height, 0), ), child: AnimatedContainer( duration: widget.duration, height: _height, width: double.infinity, child: _isLoading ? const LinearProgressIndicator() : widget.child, ), ), ], ), ); } }