ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Flutter-StatelessWidget与StatefulWidget的使用说明

2020-02-21 19:41:04  阅读:358  来源: 互联网

标签:StatefulWidget Widget response json StatelessWidget initState build data Flutter


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: <Widget>[
            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 createState()函数,实现createState的过程中,可以通过State来集成一个有状态的Widget。

这里先来创建一个有状态的Wdget:StateFulWidgetDemo1:

class StateFulWidgetDemo1 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => StateFulWidgetDemo1State();

}

然后再实现createState()函数,需要定义一个集成自State的widget

class StateFulWidgetDemo1State extends State<StateFulWidgetDemo1> {
  @override
  Widget build(BuildContext context) {
    print('build-----${_data_colors.length}');
    // TODO: implement build
    return null;
  }
}

到此就创建成了一个有状态的Widget。

下面需要向里面增加一些内容。

这里通过一个悬浮按钮来实现向当前WIdget里面添加内容。首先我们先实现initState函数,这个函数只会在创建当前Widget的函数调用一次

List<Color> _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<StatefulWidget> createState() => StateFulWidgetDemo1State();

}
class StateFulWidgetDemo1State extends State<StateFulWidgetDemo1> {
  List<Color> _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<DataModel> datas = responseBody.map<DataModel>((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<StatefulWidget> createState() => StateFulWidgetDemo2State();
}

class StateFulWidgetDemo2State extends State<StateFulWidgetDemo2> {
  List<DataModel> _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<DataModel> datas = responseBody.map<DataModel>((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<Widget> _getGridView() {
    List<Widget> datas = new List();
   return _dataModel.map<Widget>((dataModel) => Container(
     alignment: Alignment.center,
     padding: EdgeInsets.only(left:10.0, right: 10.0),
//     height: 100.0,
//     color: Colors.redAccent,
     child: Stack(
       children: <Widget>[
         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<List<DataModel>> 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<DataModel> datas = responseBody.map<DataModel>((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<StatefulWidget> createState() => StateFulWidgetDemo3State();
}

class StateFulWidgetDemo3State extends State<StateFulWidgetDemo3> {
  Future<List<DataModel>> 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<DataModel> datas = responseBody.map<DataModel>((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<List<DataModel>> 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<Widget>((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: <Widget>[
                        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一样,这里就不再给出。

嗨哒哥 发布了18 篇原创文章 · 获赞 0 · 访问量 329 私信 关注

标签:StatefulWidget,Widget,response,json,StatelessWidget,initState,build,data,Flutter
来源: https://blog.csdn.net/lvsonghai/article/details/104433321

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有