Flutter-StatelessWidget与StatefulWidget的使用说明
在Flutter中Widget一共分为两种:
1、StatelessWidget 无状态Widget
2、StatefulWidget 有状态Widget
无状态Widget,就是说一旦这个Widget创建完成,状态就不允许再变动。
有状态Widget,就是说当前Widget创建完成之后,还可以对当前Widget做更改,可以通过setState函数来刷新当前Widget来达到有状态。
StatelessWidget的实现
在需要实现一个StatelessWidget组件的时候,声明一个class类StateLessDemo需要通过extends继承StatelessWidget,然后实现build方法,就可以创建一个无状态的Widget。这个Widget创建完成后,Widget的状态就固定了,当前Widget就是一个无状态的,当前Widget
的内容固定,不可更改。
注意:如果无状态Widget里面有子Widget,并且子Widget是有状态的,则子Widget的内容是可以通过setState来更改的。无状态Widget影响的仅仅是自己是无状态的,不回影响他的父Widget和子Widget。
无状态Widget是不能调用setState函数
这里给出一个简单的例子,创建一个Column容器,在里面放入三个Container,颜色分别为黑色、黄色、红色:
class StateManagerDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
color: Colors.white,
home: StateLessDemo(),
);
}
}
class StateLessDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('状态管理Widget'),
backgroundColor: Colors.orange,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 10.0,),
Container(
height: 100.0,
color: Colors.black,
),
SizedBox(height: 10.0,),
Container(
height: 100.0,
color: Colors.yellowAccent,
),
SizedBox(height: 10.0,),
Container(
height: 100.0,
color: Colors.redAccent,
),
],
),
),
);
}
}
这个无状态StateLessDemo Widget一旦声明,就变得不可更改。
运行结果如下:
StatefulWidget的实现方式1
StatefulWidget组件的实现相对于StatelessWidget来说,复杂那么一点点。首先也是要通过extends继承StatefulWidget,然后实现State
这里先来创建一个有状态的Wdget:StateFulWidgetDemo1:
class StateFulWidgetDemo1 extends StatefulWidget {
@override
State createState() => StateFulWidgetDemo1State();
}
然后再实现createState()函数,需要定义一个集成自State的widget
class StateFulWidgetDemo1State extends State {
@override
Widget build(BuildContext context) {
print('build-----${_data_colors.length}');
// TODO: implement build
return null;
}
}
到此就创建成了一个有状态的Widget。
下面需要向里面增加一些内容。
这里通过一个悬浮按钮来实现向当前WIdget里面添加内容。首先我们先实现initState函数,这个函数只会在创建当前Widget的函数调用一次
List _data_colors;
Random _random;//随机
@override
void initState() {
print('initState');
// TODO: implement initState
super.initState();
_random = Random(255);
_data_colors = new List();
// _data_colors.add(Color.fromARGB(_random.nextInt(255), _random.nextInt(255), _random.nextInt(255), 1));
}
在initState函数中,初始化一个数据函数和一个空的List数组,这个数组里面将会存放一个Color对象。
然后在build函数中,创建一个悬浮按钮,当每次点击悬浮按钮的时候,会向_data_colors数组中添加一个Color对象,然后再手动调用setState函数去刷新Widget;显示这组_data_colors的对象这里使用ListView对象,就能看到每点击一次悬浮按钮,ListView里面的数据就会多一行。
完整代码实现如下:
class StateFulWidgetDemo1 extends StatefulWidget {
@override
State createState() => StateFulWidgetDemo1State();
}
class StateFulWidgetDemo1State extends State {
List _data_colors;
Random _random;
@override
void initState() {
print('initState');
// TODO: implement initState
super.initState();
_random = Random(255);
_data_colors = new List();
// _data_colors.add(Color.fromARGB(_random.nextInt(255), _random.nextInt(255), _random.nextInt(255), 1));
}
@override
Widget build(BuildContext context) {
print('build-----${_data_colors.length}');
// TODO: implement build
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: (){
setState(() {
_data_colors.add(Color.fromARGB(_random.nextInt(255), _random.nextInt(255), _random.nextInt(255), 1));
});
},
child: Icon(Icons.add),
),
appBar: AppBar(
title: Text('状态管理Widget'),
backgroundColor: Colors.orange,
),
body: Center(
child: ListView.separated(
itemBuilder: (BuildContext context, int index){
return ListTile(
title: Text('第$index..个Text',style: TextStyle(
fontSize: 20.0,
color: _data_colors[index]
),),
subtitle: Text('第$index..个subtitle。。。。。。。'),
);
},
separatorBuilder: (context, index) => Divider(),
itemCount: _data_colors.length == 0 ? 0 : _data_colors.length
),
),
);
}
}
StatefulWidget的实现方式2
StatefulWidget多用于需要对当前Widget内容做变动的时候,有变动就离不开对数据做网络请求,接下来将会使用网络请求下来的数据进行渲染Widget。
准备工作,加入pubspec.yaml中网络请求库:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
http: ^0.12.0+4
然后再使用的地方导入:
import 'package:http/http.dart' as http;
接着就是声明一个有状态的StateFulWidgetDemo2,在initState中进行网络接口调用:
@override
initState() {
// TODO: implement initState
super.initState();
getData();
}
Future getData() async {
final response =
await http.get('https://raw.githubusercontent.com/LVHAI/TestData/master/flutter_data.json');
if (response.statusCode == 200) {
print('object............${response.body}');
final responseBody = json.decode(response.body);
List datas = responseBody.map((json) => DataModel.changeToModel(json)).toList();
print('object............$datas');
setState(() {//更新状态
_dataModel = datas;
});
return datas;
} else {
throw Exception('Failed to fetch posts.');
}
}
在数据请求回来之后,用到了一个DataModel模型,DataModel中实现了json转model的实现:
class DataModel{
final String title;
final String subTitle;
final String imageUrl;
DataModel(
this.title,
this.subTitle,
this.imageUrl);
DataModel.changeToModel(Map jsonMap)
:title=jsonMap['title'],
subTitle=jsonMap['subTitle'],
imageUrl=jsonMap['imageUrl'];
}
最后通过调用setState把得到的模型数据渲染到Widget中。
完整代码如下:
class StateFulWidgetDemo2 extends StatefulWidget {
@override
State createState() => StateFulWidgetDemo2State();
}
class StateFulWidgetDemo2State extends State {
List _dataModel = new List();
@override
initState() {
// TODO: implement initState
super.initState();
getData();
}
Future getData() async {
final response =
await http.get('https://raw.githubusercontent.com/LVHAI/TestData/master/flutter_data.json');
if (response.statusCode == 200) {
print('object............${response.body}');
final responseBody = json.decode(response.body);
List datas = responseBody.map((json) => DataModel.changeToModel(json)).toList();
print('object............$datas');
setState(() {//更新状态
_dataModel = datas;
});
return datas;
} else {
throw Exception('Failed to fetch posts.');
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('状态管理Widget'),
backgroundColor: Colors.orange,
),
body: Center(
child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: 2.1,
mainAxisSpacing: 16.0,
crossAxisSpacing: 10.0
),
children: _getGridView(),
),
),
);
}
List _getGridView() {
List datas = new List();
return _dataModel.map((dataModel) => Container(
alignment: Alignment.center,
padding: EdgeInsets.only(left:10.0, right: 10.0),
// height: 100.0,
// color: Colors.redAccent,
child: Stack(
children: [
Image.network(dataModel.imageUrl,fit: BoxFit.cover,),
Positioned(
left: 16.0,
top: 16.0,
child: Container(
child: Text(dataModel.title, style: TextStyle(
color: Colors.red,
fontSize: 20.0,
fontWeight: FontWeight.bold
),),
)),
Positioned(
left: 16.0,
right: 16.0,
top: 40.0,
// height: 60,
child: Text(dataModel.subTitle, style: TextStyle(
color: Colors.white,
fontSize: 14.0,
),))
],
),
)).toList();
}
}
运行结果展示:
StatefulWidget的实现方式3--FutureBuilder
对上面获取网络数据的实现方式做一下变动,接下来将会使用FutureBuilder的方式来创建Widget。
首先还是声明一个StateFulWidgetDemo3有状态的Widget;
然后实现网络请求:
Future> getData() async {
final response =
await http.get('https://raw.githubusercontent.com/LVHAI/TestData/master/flutter_data.json');
if (response.statusCode == 200) {
print('object............${response.body}');
final responseBody = json.decode(response.body);
List datas = responseBody.map((json) => DataModel.changeToModel(json)).toList();
print('object............$datas');
return datas;
} else {
throw Exception('Failed to fetch posts.');
}
}
最后一步,实现FutureBuilder这个Widget,在FutureBuilder中有一个build函数,可以在这个函数中监听到网络请求的状态:
enum ConnectionState {
/// Not currently connected to any asynchronous computation.
///
/// For example, a [FutureBuilder] whose [FutureBuilder.future] is null.
none,
/// Connected to an asynchronous computation and awaiting interaction.
waiting,
/// Connected to an active asynchronous computation.
///
/// For example, a [Stream] that has returned at least one value, but is not
/// yet done.
active,
/// Connected to a terminated asynchronous computation.
done,
}
通过判断上面集中状态来实现自己需求。
完整代码如下:
class StateFulWidgetDemo3 extends StatefulWidget {
@override
State createState() => StateFulWidgetDemo3State();
}
class StateFulWidgetDemo3State extends State {
Future> getData() async {
final response =
await http.get('https://raw.githubusercontent.com/LVHAI/TestData/master/flutter_data.json');
if (response.statusCode == 200) {
print('object............${response.body}');
final responseBody = json.decode(response.body);
List datas = responseBody.map((json) => DataModel.changeToModel(json)).toList();
print('object............$datas');
return datas;
} else {
throw Exception('Failed to fetch posts.');
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('状态管理Widget'),
backgroundColor: Colors.orange,
),
body: FutureBuilder(
future: getData(),
builder: (BuildContext context, AsyncSnapshot> snapData) {
if(snapData.connectionState == ConnectionState.waiting) {
return Container(
alignment: Alignment.center,
color: Colors.grey,
child: Text('Loading......',style: TextStyle(
decoration: TextDecoration.none
),),
);
}
return ListView(
children: snapData.data.map((dataModel){
return Container(
color: Colors.white,
padding: EdgeInsets.only(left: 16.0,right: 16.0,top: 16.0),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(image: NetworkImage(dataModel.imageUrl),fit: BoxFit.cover),
borderRadius: BorderRadius.circular(8.0)
),
height: 160.0,
child: Stack(
children: [
Positioned(
left: 16.0,
top: 16.0,
child: Text(dataModel.title, style: TextStyle(
color: Colors.red,
fontSize: 20.0,
fontWeight: FontWeight.bold,
decoration: TextDecoration.none
),)),
Positioned(
left: 16.0,
right: 16.0,
top: 40.0,
// height: 60,
child: Text(dataModel.subTitle, style: TextStyle(
color: Colors.white,
fontSize: 14.0,
decoration: TextDecoration.none
),))
],
),
),
);
}).toList(),
);
}
),
);
}
上述中使用DataModel模型请在上面查找。具体的运行结果跟StatefulWidget的实现方式2一样,这里就不再给出。