如何在Flutter中使用进度指示器? [英] How to work with progress indicator in flutter?
问题描述
我是新手,但想知道在布局中添加 CircularProgressIndicator
的更好方法是什么。例如,我的登录视图。该视图具有用户名,密码和登录按钮。我确实想创建一个覆盖布局(具有 Opacity
),该布局在加载时显示进度指示器,就像我在NativeScript中使用的一样,但是我对如何做也不太困惑如果是更好的方法。例如,在NativeScript上,我在主布局中添加了IndicatorActivity,并将busy设置为true或false,以便在加载时覆盖所有视图组件。
I'm newbie in flutter and wanted to know what is better way to add CircularProgressIndicator
in my layout. For example, my login view. This view have username, password and login Button. I did want create a overlay layout (with Opacity
) that, when loading, show progress indicator like I use in NativeScript, but I'm little confused with how to do and too if it is the better way. On NativeScript, for example, I add IndicatorActivity in main layout and set busy to true or false, so it overlay all view components when is loading.
编辑:
我能够达到以下结果:
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _loading = false;
void _onLoading() {
setState(() {
_loading = true;
new Future.delayed(new Duration(seconds: 3), _login);
});
}
Future _login() async{
setState((){
_loading = false;
});
}
@override
Widget build(BuildContext context) {
var body = new Column(
children: <Widget>[
new Container(
height: 40.0,
padding: const EdgeInsets.all(10.0),
margin: const EdgeInsets.fromLTRB(15.0, 150.0, 15.0, 0.0),
decoration: new BoxDecoration(
color: Colors.white,
),
child: new TextField(
decoration: new InputDecoration.collapsed(hintText: "username"),
),
),
new Container(
height: 40.0,
padding: const EdgeInsets.all(10.0),
margin: const EdgeInsets.all(15.0),
decoration: new BoxDecoration(
color: Colors.white,
),
child: new TextField(
decoration: new InputDecoration.collapsed(hintText: "password"),
),
),
],
);
var bodyProgress = new Container(
child: new Stack(
children: <Widget>[
body,
new Container(
alignment: AlignmentDirectional.center,
decoration: new BoxDecoration(
color: Colors.white70,
),
child: new Container(
decoration: new BoxDecoration(
color: Colors.blue[200],
borderRadius: new BorderRadius.circular(10.0)
),
width: 300.0,
height: 200.0,
alignment: AlignmentDirectional.center,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Center(
child: new SizedBox(
height: 50.0,
width: 50.0,
child: new CircularProgressIndicator(
value: null,
strokeWidth: 7.0,
),
),
),
new Container(
margin: const EdgeInsets.only(top: 25.0),
child: new Center(
child: new Text(
"loading.. wait...",
style: new TextStyle(
color: Colors.white
),
),
),
),
],
),
),
),
],
),
);
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Container(
decoration: new BoxDecoration(
color: Colors.blue[200]
),
child: _loading ? bodyProgress : body
),
floatingActionButton: new FloatingActionButton(
onPressed: _onLoading,
tooltip: 'Loading',
child: new Icon(Icons.check),
),
);
}
}
我仍在适应状态的想法。
I'm still adapting to the idea of states. This code is within the expected when working with flutter?
谢谢!
推荐答案
在扑朔迷离中,有几种方法可以处理异步动作。
In flutter, there are a few ways to deal with Asynchronous actions.
一种懒惰的方法是使用模式。这将阻止用户输入,从而防止任何不必要的操作。
这几乎不需要更改代码。只需将您的 _onLoading
修改为以下内容:
A lazy way to do it can be using a modal. Which will block the user input, thus preventing any unwanted actions.
This would require very little change to your code. Just modifying your _onLoading
to something like this :
void _onLoading() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: new Row(
mainAxisSize: MainAxisSize.min,
children: [
new CircularProgressIndicator(),
new Text("Loading"),
],
),
);
},
);
new Future.delayed(new Duration(seconds: 3), () {
Navigator.pop(context); //pop dialog
_login();
});
}
最理想的方法是使用 FutureBuilder
和有状态的小部件。这是您开始的。
诀窍在于,您可以直接使用 Future< MyUser>来代替状态中的
boolean加载= false
。用户
The most ideal way to do it is using FutureBuilder
and a stateful widget. Which is what you started.
The trick is that, instead of having a boolean loading = false
in your state, you can directly use a Future<MyUser> user
,然后将其作为参数传递给 FutureBuilder
,它将为您提供一些信息,例如 ; hasData或完成后的 MyUser
实例。
And then pass it as argument to FutureBuilder
, which will give you some info such as "hasData" or the instance of MyUser
when completed.
这将导致如下所示:
@immutable
class MyUser {
final String name;
MyUser(this.name);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<MyUser> user;
void _logIn() {
setState(() {
user = new Future.delayed(const Duration(seconds: 3), () {
return new MyUser("Toto");
});
});
}
Widget _buildForm(AsyncSnapshot<MyUser> snapshot) {
var floatBtn = new RaisedButton(
onPressed:
snapshot.connectionState == ConnectionState.none ? _logIn : null,
child: new Icon(Icons.save),
);
var action =
snapshot.connectionState != ConnectionState.none && !snapshot.hasData
? new Stack(
alignment: FractionalOffset.center,
children: <Widget>[
floatBtn,
new CircularProgressIndicator(
backgroundColor: Colors.red,
),
],
)
: floatBtn;
return new ListView(
padding: const EdgeInsets.all(15.0),
children: <Widget>[
new ListTile(
title: new TextField(),
),
new ListTile(
title: new TextField(obscureText: true),
),
new Center(child: action)
],
);
}
@override
Widget build(BuildContext context) {
return new FutureBuilder(
future: user,
builder: (context, AsyncSnapshot<MyUser> snapshot) {
if (snapshot.hasData) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Hello ${snapshot.data.name}"),
),
);
} else {
return new Scaffold(
appBar: new AppBar(
title: new Text("Connection"),
),
body: _buildForm(snapshot),
);
}
},
);
}
}
这篇关于如何在Flutter中使用进度指示器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!