Flutter-StatelessWidget与StatefulWidget的使用说明

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一旦声明,就变得不可更改。
运行结果如下:


statelessdemo1.jpg

StatefulWidget的实现方式1

StatefulWidget组件的实现相对于StatelessWidget来说,复杂那么一点点。首先也是要通过extends继承StatefulWidget,然后实现State<StatefulWidget> 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
        ),
      ),
    );
  }
}
statedemo1.gif

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();
  }
}

运行结果展示:


getdatafromhttp.jpg

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一样,这里就不再给出。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容