[Flutter Widget] StatefulWidget

Posted flutter开发者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Flutter Widget] StatefulWidget相关的知识,希望对你有一定的参考价值。

在前面的文章中我们学习了许多的控件,但是无一例外他们都不能处理界面的动态变更,我们无法在界面初始化后根据用户的操作去更改界面的展示方式。

是的这是一个很大的问题,但是在Flutter我们可以借助于StatefulWidget组件来完成界面的变更。

StatefulWidget又被称为有状态组件,开发者可以根据用户的操作来选择性的更新界面上的组件。

大家是否还记得我们每次创建项目,系统都会默认给我们生成的程序

每次当点击下面的FloatActionButton上面的数字就会+1

还是来看下官方代码是怎么实现的(为了便于大家理解我们去除了英文注释和无用参数设置)

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
 @override
 
Widget build(BuildContext context) {
   return new MaterialApp(
     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> {
 int _counter = 0;

 
void _incrementCounter() {
   setState(() {
     _counter++;
   
});
 
}
 @override
 
Widget build(BuildContext context) {
   return new Scaffold(
     appBar: new AppBar(

       title: new Text(widget.title),
     
),
     
body: new Center(
       child:
       new Text(
         '$_counter',
         
style: Theme.of(context).textTheme.display1,
       
),
     
),
     
floatingActionButton: new FloatingActionButton(
       onPressed: _incrementCounter,
       
child: new Icon(Icons.add),
     
),
   
);
 
}
}

代码很长对吧,希望大家不要被上面的代码吓到,其实还是跟原来的StatelessWidget的流程是一样的,只不过多了一个设置State的中间件而已。咱们来一点一点看下代码。

首先新建了一个App对象继承于StatelessWidget,返回了一哥MyHomePage对象。

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
 @override
 
Widget build(BuildContext context) {
   return new MaterialApp(
     home: new MyHomePage(title: 'Flutter Demo Home Page'),
   
);
 
}
}

MyHomePage对象继承于StateFulWdiget,但是继承StateFulWidget组件默认要返回继承于State的Wdiget,所以,MyHomePage又返回了一个_MyHomePageState对象


@override
_MyHomePageState createState() => new _MyHomePageState();
}

_MyHomePageState继承于State ,同样它需要返回真正页面上展示的内容,但是这个组件内你可以调用 setState(() {})的回调函数来实现界面效果的更新。

void _incrementCounter() {
 setState(() {
   _counter++;
 
});
}

每当我们点击FloatActionButton按钮都会调用_incrementCounter方法,_incrementCounter方法会调用setState方法更新计数器的counter使其值+1,并且更新界面上View的状态。


由于界面上的Text的值是依据_counter的,所以每次更新界面都会显示最新的_counter的值,这样就达到了更新界面的效果。

关于点击事件

在上面的代码中大家可以看到floatingActionButton的onPressed点击事件我们传入了_incrementCounter,甚至连“()”也没有写。


从floatingActionButton的构造方法中我们可以看到,onPress需要传入的是一个没有返回值,没有参数的方即VoidCallback。

正好 _incrementCounter方法就是这么一个方法,所以我们可以直接把方法当做参数传入onPressed中。


举个例子


为了方便大家理解这个有状态组件,我们再来举个例子


内容区域是一个IndexedStack(栈里面依次放几个图标),默认加载第一个入栈的元素。下面是一个FloAtionButton,没当点击这个按钮是更新IndexedStack当前现实的元素位置,在这里我们使用Random来随机显示栈内Icons。

接下来,我们来看下代码:

void main() {
 runApp(new MaterialApp(
   home: new MyHome(),
 
));
}

class MyHome extends StatefulWidget {
 @override
 
State<StatefulWidget> createState() {
   return new MyHomeState();
 
}
}

首先,我们创建一个MyHome Widget继承于StatefulWidget,返回一个具有状态的MyhomeState组件。

class MyHomeState extends State<MyHome> {
 int currentIndex = 0;

 
void  _onFloatActionButtonPressed() {
   setState(() {
     currentIndex =new Random().nextInt(4);
   
});
 
}


@override
 
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("StatefulWidget"),
     
),
     
body: new Center(
child: new IndexedStack(
index: currentIndex,
           
children: <Widget>[
new Icon(
Icons.cloud_download,
               
size: 100.0,
               
color: Colors.blue,
             
),
             
new Icon(
Icons.error_outline,
               
size: 100.0,
               
color: Colors.red,
             
),
             
new Icon(
Icons.check_circle,
               
size: 100.0,
               
color: Colors.green,
             
),
             
new Icon(
Icons.help,
               
size: 100.0,
               
color: Colors.yellowAccent,
             
)
],
         
)),
     
floatingActionButton: new FloatingActionButton(
onPressed: _onFloatActionButtonPressed,
       
child: new Icon(Icons.track_changes),
       
backgroundColor: Colors.blueAccent,
     
),
   
);
 
}
}

在MyHomeState中我们声明了一个变量currentIndex来记录栈内当前位置的值。

内部body是一个居中的IndexedStack,下面是一个floatingActionButton,每当我们点击这个按钮都会调用 _onFloatActionButtonPressed方法,更新currentIndex的值,然后更细UI显示效果。


[Flutter Widget] StatefulWidget

上面的例子很简单,大家在平时的开发中可以根据用户操作的状态来显示指定的页面,如加载中、加载成功、加载失败、网络异常等状态。

小结


  1. StateFulWidget是有状态组件,负责处理有状态的界面

  2. 使用setState回调可以很轻松的更新界面上UI的显示效果

  3. 有状态组件变更归根到底是根据数据变更来做的操作

  4. VoidCallback是一个没有参数没有返回值的方法

试一试


今天的内容很简单,但是还是需要熟悉Flutter中有状态组件的用法,因为这个是最重要的概念哦。
那么大家试一试官方Demo让中间计数器的字体大小随着计数器的值变化。


[Flutter Widget] StatefulWidget


当然,有什么问题也欢迎大家在后台留言,我会在看到的第一时间回复大家的




以上是关于[Flutter Widget] StatefulWidget的主要内容,如果未能解决你的问题,请参考以下文章

Flutter控件篇(Stateful widget)——ListView

Flutter - Stateful(有状态) 和 stateless(无状态) widgets

跨多个屏幕使用的 Flutter Stateful Widget 正在重建

Flutter Stateful Widget 状态未初始化

Flutter Stateful Widget 重新创建 State

Flutter: Stateful 挂件 vs Stateless 挂件