Reputation: 3996
I want to display a circular bar like loading in front of other widgets. Below is the code which i am currently using. It shows the Circular loading but its between other widget.
It should be on top. Based on the suggestion I tried using Stack but it is still showing in between the widget. What am I doing wrong here?
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool visible = true ; //Testing purpose it is true. Actually it is false.
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Stack(
children: <Widget>[
new Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: FractionalOffset.bottomCenter,//Alignment.bottomLeft,
colors: [Colors.green[900], Colors.lightBlueAccent]),
),
),SingleChildScrollView(
child: new Form(
key: _formKey,
autovalidate: _autoValidate,
child: Center(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
VerticalText(),
TextLogin(),
],
),
Divider(),
Container(
width: 280,
),
Container(
width: 280,
child: TextFormField(
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Email',
fillColor: Colors.lightBlueAccent,
labelText: 'Email',
labelStyle: TextStyle(
color: Colors.white70,
fontSize: 20,
),
),
controller: emailController,
autocorrect: true,
validator: validateEmail,
onSaved: (String val) {
_email = val;
},
)
),
Container(
width: 280,
child: TextFormField(
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Password',
fillColor: Colors.lightBlueAccent,
labelText: 'Password',
labelStyle: TextStyle(
color: Colors.white70,
fontSize: 20,
),
),
controller: passwordController,
autocorrect: true,
obscureText: true,
validator: validatePassword,
onSaved: (String val) {
_password = val;
},
)
),
RaisedButton(
onPressed: _validateInputs,
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Text('Login'),
),
Visibility(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
],
),
),
visible: visible,
),
],
),
)
)
)
],
),
);
}
I have seen similar questions in SO but still getting hard time to resolve it.
How to work with progress indicator in flutter?
flutter how to get a circular progress indicator working
Flutter : create an overlay progress bar
How to display CircularProgressIndicator on top of all widget in a centre of the screen
Upvotes: 8
Views: 19137
Reputation: 441
As above most of them gave answer to make separate reusable function. So here is mine if you want to fetch some data and display circular progress indicator while data is being fetched.
///Function to get data from a future and display a dialog with circlular progress indicator while data is fetched.
getFutureData(BuildContext context, var future) async {
var data;
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => Center(
child: FutureBuilder(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
Navigator.pop(context);
}
return CircularProgressIndicator();
},
),
),
);
return data;
}
Upvotes: 1
Reputation: 4091
Like said, the real meaning of CircularProgressIndicator
is to be run while loading a process without letting user interrupt.
Create this loading indicator as a reusable .dart file.
With this you can use the LoadingIndicator flexible everywhere and overlay the current screen.
You just have to make a .dart file containing:
import 'package:flutter/material.dart';
buildLoading(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
),
);
});
}
Then you can use it anywhere using
buildLoading(context);
and dismiss it when loading is done using
Navigator.of(context).pop();
Upvotes: 11
Reputation: 2956
The real meaning of circularProgressIndicator is to be run while loading process without letting user interrupt.
To remove interruption by user in between, one should put circularProgressIndicator in a dialog with property barrierDismissible: false
.
One should create this loading indicator as reusable widget.
You can craete a method like below and can use it anywhere over the screen without defining in screen. (this does not require stack also.). Dialog will appear on the center of the screen.
buildShowDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Center(
child: CircularProgressIndicator(),
);
});
}
For Reference: Checkout code below:
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Demo(),
);
}
}
class Demo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Circle Progress Indicator Demo"),
),
body: Center(
child: MaterialButton(
child: Text("Press Me!"),
onPressed: () => buildShowDialog(context),
),
),
);
}
buildShowDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Center(
child: CircularProgressIndicator(),
);
});
}
}
Upvotes: 22
Reputation: 3996
I removed Visiblity
code with this one.
Old Code
Visibility(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
],
),
),
visible: visible,
),
New Code
visible ? Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child:SizedBox(// Center(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
),
)
: Container()
And most importantly it needs to call in the first Widget.
return Scaffold(
key: _scaffoldKey,
body: Stack(
children: <Widget>[
/////Some containers,child Widget etc/////////
visible ? Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child:SizedBox(// Center(
child: CircularProgressIndicator(
strokeWidth: 4.0,
valueColor : AlwaysStoppedAnimation(Colors.white),
),
height: 200.0,
width: 200.0,
),
),
)
: Container()
] //Widget
), //Stack
); //Scaffold
I am not sure i explained it properly or not. But Bottom line is it shouldn't be inside the other child widget.
It should be placed inside first children: <Widget>[
not inside the nested.
Upvotes: 1
Reputation: 1347
You can use Positioned
Widget in Stack
Widget for Showing CircularProgressIndicator
in front of all widgets like below..
Please put values according to your convenience in all four values bottom,left,right,top...
Positioned(
bottom: ,
left: ,
right: ,
top : ,
child: Container(
child : CircularProgressIndicator()
)
...
)
Upvotes: 3