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

这里先来创建一个有状态的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
        ),
      ),
    );
  }
}
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 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();
  }
}

运行结果展示:


getdatafromhttp.jpg

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

你可能感兴趣的:(Flutter-StatelessWidget与StatefulWidget的使用说明)