Flutter is officially out, and as an Android developer, it’s time to follow suit. When you write a login page, you finish the login and suddenly realize that you don’t know how to create a loading animation. After all, Android ProgressDialog is available, but you don’t know what to use in the Flutter.
The project address
The target
First, the effect picture:
Does it feel like ProgressDialog?!
Implementation approach
Use dialog
The first thing that came to mind was to use the SimpleDialog dialog box that came with Flutter, but that didn’t suit me when I thought that Flutter seemed to close by clicking a button.
Return different layouts depending on the situation
Return the loaded layout when loaded, and return the landing page layout when not loaded, with the following code:
import 'package:flutter/material.dart';
import 'package:flutter_loading/Toast.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Load animation')); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { bool _loading =false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _childLayout(),
);
}
Widget _childLayout() {
if (_loading) {
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
} else {
return Center(
child: RaisedButton(
onPressed: () => _onRefresh(),
child: Text('Show loading animation'),),); } } Future<Null> _onRefresh() async {setState(() { _loading = ! _loading; }); await Future.delayed(Duration(seconds: 3), () {setState(() { _loading = ! _loading; Toast.show(context,"Load complete"); }); }); }}Copy the code
The _childLayout() method returns the ring progress bar while loading. When loading is complete, the actual layout is returned. The code looks like this:
The effect seems to be achieved, but this effect is only suitable for ordinary data list page loading, if the login page, you can not do so, a login page layout is gone, only a circle what is meaningful. That doesn’t work either.
Use a Stack layout
Overlay a translucent background on top of the original layout to display a progress bar. The idea seems to work. The point is to start with a cascade layout with at least two controls. According to the idea of Flutter, everything is a control. We define a custom control called ProgressDialog. Our control accepts two mandatory parameters: child and whether to display loading progress: Loading. These two parameters are required, so the custom control looks like this
import 'package:flutter/material.dart'; class ProgressDialog extends StatelessWidget { final bool loading; final Widget child; ProgressDialog({Key key, @required this.loading, @required this.child}) : assert(child ! = null), assert(loading ! = null), super(key: key); @override Widget build(BuildContext context) {returnnull; }}Copy the code
The Stack layout must return more than two controls, so define a List of controls to hold the stacked group of controls. Add the Child control to the List and an animation to load. The code:
import 'package:flutter/material.dart'; class ProgressDialog extends StatelessWidget { final bool loading; final Widget child; ProgressDialog({Key key, @required this.loading, @required this.child}) : assert(child ! = null), assert(loading ! = null), super(key: key); @override Widget build(BuildContext context) { List<Widget> widgetList = []; widgetList.add(child); // If it is loading, display the loading layoutif (loading) {
widgetList.add(Center(
child: CircularProgressIndicator(),
));
}
returnStack( children: widgetList, ); }}Copy the code
Doesn’t it feel like it’s easy, the convention is shown above:
At least the original layout has not been directly replaced, but it does not feel beautiful. Ok, add a transparent background effect, which uses the Opacity control here, and is specially used to draw the transparent effect. The code:
import 'package:flutter/material.dart'; class ProgressDialog extends StatelessWidget { final bool loading; final Widget child; ProgressDialog({Key key, @required this.loading, @required this.child}) : assert(child ! = null), assert(loading ! = null), super(key: key); @override Widget build(BuildContext context) { List<Widget> widgetList = []; widgetList.add(child); // If it is loading, display the loading layoutifAdd (Opacity(Opacity: 0.8, child: ModalBarrier(color: color.black87,)),); / / circular progress bar widgetList. Add (Center (child: CircularProgressIndicator (),)); }returnStack( children: widgetList, ); }}Copy the code
The old rules, above:
Does it look similar? The progress is generally ok, but what if I want to display text at the bottom of the progress bar? And I think that toast looks good and I want to make it like that. Well, in that case, the loading progress bar should be on the same level as the prompt content. Using a vertical layout to display each progress and a Text() should do the trick:
import 'package:flutter/material.dart'; class ProgressDialog extends StatelessWidget { final bool loading; final Widget child; ProgressDialog({Key key, @required this.loading, @required this.child}) : assert(child ! = null), assert(loading ! = null), super(key: key); @override Widget build(BuildContext context) { List<Widget> widgetList = []; widgetList.add(child); // If it is loading, display the loading layoutifAdd (Opacity(Opacity: 0.8, child: ModalBarrier(color: color.black87,)),); Add (Center(child: Container(padding: const EdgeInsets. All (20.0), decoration: BoxDecoration(// black background color: color.black87, // borderRadius: borderRadius. Circular (10.0)), child: The Column (/ / controls content inside the spindle axis drama shows mainAxisAlignment: mainAxisAlignment. Center, crossAxisAlignment: CrossAxisAlignment center, / / spindle height minimum mainAxisSize: mainAxisSize. Min, the children: <Widget>[ CircularProgressIndicator(), Text('Loading... ',
style: TextStyle(color: Colors.white),
)
],
),
),
));
}
returnStack( children: widgetList, ); }}Copy the code
Wrap the progress bar and prompt content in a vertical layout Column. Perfect solution.
The prompt font should be customizable, and the loading animation should be customizable, so the final code is as follows:
import 'package:flutter/material.dart'; Class ProgressDialog extends StatelessWidget {// Final Widget child; // Whether final bool loading is displayed; // Final String MSG; // Loading animation final Widget progress; // Background opacity final double alpha; // Final Color textColor; ProgressDialog( {Key key, @required this.loading, this.msg, this.progress = const CircularProgressIndicator(), This.alpha = 0.6, this.textcolor = colors.white, @required this.child}) : Assert (child! = null), assert(loading ! = null), super(key: key); @override Widget build(BuildContext context) { List<Widget> widgetList = []; widgetList.add(child);if (loading) {
Widget layoutProgress;
if (msg == null) {
layoutProgress = Center(
child: progress,
);
} else{layoutProgress = Center(child: Container(padding: const EdgeInsets. All (20.0), decoration: BoxDecoration(color: decoration) Color.black87, borderRadius: borderRadius. Circular (4.0)), Child: Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[progress, Container(padding: const EdgeInsets. FromLTRB (10.0, 10.0, 10.0, 0)), child: Text(MSG, style: TextStyle(color: textColor, fontSize: 16.0),)],),),); } widgetList.add(Opacity( opacity: alpha, child: new ModalBarrier(color: Colors.black87), )); widgetList.add(layoutProgress); }returnStack( children: widgetList, ); }}Copy the code
Finally, attach the example code called in the project:
import 'package:flutter/material.dart';
import 'package:flutter_loading/Toast.dart';
import 'package:flutter_loading/view_loading.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Load animation')); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { bool _loading =false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ProgressDialog(
loading: _loading,
msg: 'Loading... ',
child: Center(
child: RaisedButton(
onPressed: () => _onRefresh(),
child: Text('Show loading animation'(), ((), ((), ((), ((), (() } Future<Null> _onRefresh() async {setState(() { _loading = ! _loading; }); await Future.delayed(Duration(seconds: 3), () {setState(() { _loading = ! _loading; Toast.show(context,"Load complete"); }); }); }}Copy the code
For loading animations, just change the progress property to a custom property. For example, we use his loading animation, the “progress” animation, just add a line to the code above (if you have to git it on Github of course) :
Loading: _loading, // Custom animation progress: MyProgress(size: new size (100.0, 20.0),color: color.white,), MSG:'Loading... '.Copy the code
The effect is as follows:
- Reference Projects:
Github.com/While1true/…
Pub.dartlang.org/packages/mo…