【Flutter从入门到实战】 ⑤、Flutter的StatelessWidget案例-列表展示、StatefulWidget 案例 - 加减操作、 Flutter的Widget生命周期

Flutter从入门到实战
一共分为23个系列
①(Flutter、Dart环境搭建篇) 共3个内容 已更新
②(Dart语法1 篇) 共4个内容 已更新
③(Dart语法2 篇) 共2个内容 已更新
④(Flutter案例开发篇) 共4个内容 已更新
⑤(Flutter的StatelessWidget 共3个内容 已更新
⑥(Flutter的基础Widget篇) 共2个内容 已更新
⑦(布局Widget篇) 共1个内容 已更新
⑧(Flex、Row、Column以及Flexible、Stack篇) 共1个内容 已更新
⑨(滚动的Widget篇) 共4个内容 已更新
⑩(Dart的Future和网络篇) 共3个内容 已更新
⑪(豆瓣案例-1篇) 共3个内容 已更新
⑫(豆瓣案例-2篇) 共3个内容 已更新

官方文档说明

官方视频教程
Flutter的YouTube视频教程-小部件

请添加图片描述

上节课回顾

  1. Scaffold 小组件
    相当于 iOS的ViewController 或者Android的 Activity
    看作一个界面
  2. AppBar 相当于 Tabbar
  3. StatelessWidget 是不能存放变量的 因为是继承 Widget 因为 Widget 使用了 @immutable 这个修饰用来 当前这个类是不可变的 或者子类是不可变的.所有的成员变量必须是 final的
  4. StatefulWidget 分成2个类
    一个是继承 StatefulWidget的类(最主要作用是 必须实现State类,还有一个作用是 可以接受父Widget 传过来的数据),
    一个是State类(状态)

①、StatelessWidget 案例 - 列表展示

1.1 使用stless代码智能提示快速创建一个继承于 StatelessWidget 的类

请添加图片描述
依次做Widget树结构

	App
	HomePage 
		-> 包含 Scaffold
		Scaffold 
		-> 包含  AppBar -> Title 
		-> 包含 body : HomeContent
	HomeContent -> Ttile

1.2 简单的Widget树结构 - Hello world 出来了

import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());

// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    return MaterialApp(
      home:YHiOSHomePage() ,
    );
  }
}

class YHiOSHomePage extends StatelessWidget {
    
    
  const YHiOSHomePage({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    // 主页 使用一个小组件 Scaffold
    return Scaffold(
      appBar: AppBar(
        title: Text("商品列表"),
      ),
      body: YHiOSHomeContent(),
    );
  }
}

class YHiOSHomeContent extends StatelessWidget {
    
    
  const YHiOSHomeContent({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    return Text("hello world");
  }
}


请添加图片描述

1.2 使用 Column Widget 创建列表商品

数据都是写死的

该代码的注意细节:

  1. 抽取列表的每一个item为Widget
  2. 定义几个变量来记录 item的数据
  3. 使用Image.network加载网络的图片
import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());

// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    return MaterialApp(
      home:YHiOSHomePage() ,
    );
  }
}

class YHiOSHomePage extends StatelessWidget {
    
    
  const YHiOSHomePage({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    // 主页 使用一个小组件 Scaffold
    return Scaffold(
      appBar: AppBar(
        title: Text("商品列表"),
      ),
      body: YHiOSHomeContent(),
    );
  }
}

class YHiOSHomeContent extends StatelessWidget {
    
    
  const YHiOSHomeContent({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    return Column(
      children: [
        YHiOSHomeProductItem("清风衬晚霞1","清风衬晚霞 desc1","https://wx3.sinaimg.cn/mw2000/515a7464ly1h01enjqtdmj20j60j6q3k.jpg"),
        YHiOSHomeProductItem("清风衬晚霞2","清风衬晚霞 desc2","https://wx2.sinaimg.cn/orj360/515a7464ly1h01enjqdo4j20j60j6t9b.jpg"),
        YHiOSHomeProductItem("清风衬晚霞3","清风衬晚霞 desc3","https://wx2.sinaimg.cn/orj360/515a7464ly1h01enjqx21j20j60j60tc.jpg"),
        YHiOSHomeProductItem("清风衬晚霞4","清风衬晚霞 desc3","https://wx2.sinaimg.cn/orj360/515a7464ly1h01enjrqa9j20j60j6q3n.jpg"),
      ],
    );
  }
}![请添加图片描述](https://img-blog.csdnimg.cn/8411a711c2a041d0b96e1fd5e78c6844.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5a6H5aScaU9T,size_18,color_FFFFFF,t_70,g_se,x_16)

// ⭐️ 抽取商品的item
/**
 * 包含 :
 * 标题
 * 详细
 * 图片
 * */
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
    
    
  final String title ;
  final String desc ;
  final String imageURL ;

  // 构造函数
  YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
  @override
  Widget build(BuildContext context) {
    
    
    return Column(
      children: [
        Text(title),
        Text(desc),
        Image.network(imageURL)
      ],
    );
  }
}


1.2 效果图

我们发现在底部多出了一块警告的区域
relayoutBoundary=up1 OVERFLOWING
布局边界
如何解决
我们需要把Column Widget 改成 ListView Widget
在这里插入图片描述
请添加图片描述

1.3 将YHiOSHomeContent Column Widget 改成 ListView Widget 效果图 就能解决上面出现的警告区域了

请添加图片描述

1.4 将通过 TextStyle 抽取字体大小、颜色 和 通过 SizedBox 设置上下的间距

class YHiOSHomeProductItem extends StatelessWidget {
    
    
  final String title ;
  final String desc ;
  final String imageURL ;

  final style1 = TextStyle(fontSize: 25,color: Colors.orange);
  final style2 = TextStyle(fontSize: 20,color: Colors.red);

  // 构造函数
  YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
  @override
  Widget build(BuildContext context) {
    
    
    return Column(
      children: [
        Text(title,style: style1),
        SizedBox(height: 8),
        Text(desc,style: style2),
        SizedBox(height: 8),
        Image.network(imageURL)
      ],
    );
  }
}

1.4 效果图

1.5 通过 alt + enter 快捷键 进行输出一个Container 对象 用来设置内外边距的 边框的大小和颜色

请添加图片描述

BoxDecoration 设置边框的大小 颜色
padding : EdgeInsets 设置边框的大小

// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
    
    
  final String title ;
  final String desc ;
  final String imageURL ;

  final style1 = TextStyle(fontSize: 25,color: Colors.orange);
  final style2 = TextStyle(fontSize: 20,color: Colors.red);

  // 构造函数
  YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
  @override
  Widget build(BuildContext context) {
    
    
    return Container(
      // decoration 装饰
      // BoxDecoration 是一个子类
      padding: EdgeInsets.all(30),
      decoration: BoxDecoration(
        border: Border.all(
          width: 5, // 设置边框的宽度
          color:Colors.purple // 设置边框的颜色
        )
      ),
      child: Column(
        children: [
          Text(title,style: style1),
          SizedBox(height: 8),
          Text(desc,style: style2),
          SizedBox(height: 8),
          Image.network(imageURL)
        ],
      ),
    );
  }
}

1.5 效果图

请添加图片描述

1.6 设置内容 不居中 通过设置交叉轴crossAxisAlignment

Column的垂直方向是主轴 |
Row的水平方向是主轴 –

// ⭐️ 抽取商品的item
/**
 * 包含 :
 * 标题
 * 详细
 * 图片
 * */
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
    
    
  final String title ;
  final String desc ;
  final String imageURL ;

  final style1 = TextStyle(fontSize: 25,color: Colors.orange);
  final style2 = TextStyle(fontSize: 20,color: Colors.red);

  // 构造函数
  YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
  @override
  Widget build(BuildContext context) {
    
    
    return Container(
      // decoration 装饰
      // BoxDecoration 是一个子类
      padding: EdgeInsets.all(30),
      decoration: BoxDecoration(
        border: Border.all(
          width: 5, // 设置边框的宽度
          color:Colors.purple // 设置边框的颜色
        )
      ),
      child: Column(
        // 主轴
        // mainAxisAlignment: MainAxisAlignment.center,
        // 交叉轴
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          Text(title,style: style1),
          SizedBox(height: 8),
          Text(desc,style: style2),
          SizedBox(height: 8),
          Image.network(imageURL)
        ],
      ),
    );
  }
}

1.6 效果图

请添加图片描述

1.7 通过包裹一个Row 使单个标题居左

可以点击指定的Widget 通过 option + enter 包裹一个row

请添加图片描述

1.7.1 单独设置Text设置居左

Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(title,style: style1),
],
),
// ⭐️ 抽取商品的item
/**
 * 包含 :
 * 标题
 * 详细
 * 图片
 * */
// 每个item的数据 都是不一样的 所以需要定义几个变量来标记数据
class YHiOSHomeProductItem extends StatelessWidget {
    
    
  final String title ;
  final String desc ;
  final String imageURL ;

  final style1 = TextStyle(fontSize: 25,color: Colors.orange);
  final style2 = TextStyle(fontSize: 20,color: Colors.red);

  // 构造函数
  YHiOSHomeProductItem(this.title,this.desc,this.imageURL);
  @override
  Widget build(BuildContext context) {
    
    
    return Container(
      // decoration 装饰
      // BoxDecoration 是一个子类
      padding: EdgeInsets.all(30),
      decoration: BoxDecoration(
        border: Border.all(
          width: 5, // 设置边框的宽度
          color:Colors.purple // 设置边框的颜色
        )
      ),
      child: Column(
        // 主轴
        // mainAxisAlignment: MainAxisAlignment.center,
        // 交叉轴
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              Text(title,style: style1),
            ],
          ),
          SizedBox(height: 8),
          Text(desc,style: style2),
          SizedBox(height: 8),
          Image.network(imageURL)
        ],
      ),
    );
  }
}

1.7 效果图

请添加图片描述


②、StatefulWidget 案例 - 加减操作

2.1 使用stful代码智能提示快速创建一个继承于 StatefulWidget 的类

请添加图片描述

StatefulWidget 中 的 Widget 和 State 注意点

  1. Widget
    StatefulWidget 是一个抽象类
    有一个方法是 必须实现的
    createState
    Widget是不加 _ 因为Wighet是暴露给别人使用的
  2. State
    State是加_ : 状态这个是给Widget使用的

Flutter设计StatefulWidget的原理

/**
* 为什么Flutter在设计的时候 StatefulWidget 的build方法放在State
* 1.build出来的Widget是需要依赖State中的变量(状态/数据)
* 2.在Flutter的运行过程中:
*  Widget是不断地销毁和创建的
*  当我们自己的状态发生改变时,并不希望重新创建一个新的State
* */

2.2 使用 Row 嵌套两个 RaisedButton按钮 用来记录加减号的

  // 为什么有些Widget是child 有些是children .最主要是看继承关系.
 // child 只是包含一个Widget
 // 有些是children 可以包含多个Widget

当代码嵌套比较多 可以使用抽取方法
比如 两个RaisedButton

  // 抽取方法 用于获取按钮
  Widget _getButtons() {
    
    
    return Row(
      children: [
        RaisedButton(
            child: Text("+"),
            color: Colors.pink,
            onPressed: () => print("点击了+")
        ),
        RaisedButton(
            child: Text("-"),
            color: Colors.orange,
            onPressed: () => print("点击了-")
        ),
      ],
    );

  }

main.dart


import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());

// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    return MaterialApp(
      home:YHiOSHomePage() ,
    );
  }
}

class YHiOSHomePage extends StatelessWidget {
    
    
  const YHiOSHomePage({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    // 主页 使用一个小组件 Scaffold
    return Scaffold(
      appBar: AppBar(
        title: Text("商品列表"),
      ),
      body: YHiOSHomeContent(),
    );
  }
}

// StatefulWidget 是一个抽象类
// 有一个方法是 必须实现的
// createState

// Widget是不加 _ 因为Wighet是暴露给别人使用的
class YHiOSHomeContent extends StatefulWidget {
    
    

  @override
  State<StatefulWidget> createState() {
    
    
    return _YHiOSHomeContentState();
  }
}

// State的代码规范是 以_开头
// State是加_ : 状态这个是给Widget使用的

/**
 * 为什么Flutter在设计的时候 StatefulWidget 的build方法放在State
 * 1.build出来的Widget是需要依赖State中的变量(状态/数据)
 * 2.在Flutter的运行过程中:
 *  Widget是不断地销毁和创建的
 *  当我们自己的状态发生改变时,并不希望重新创建一个新的State
 * */
class _YHiOSHomeContentState extends State<YHiOSHomeContent> {
    
    
  int _counter = 0;
  @override
  Widget build(BuildContext context) {
    
    
    return Center(
      // 为什么有些Widget是child 有些是children .最主要是看继承关系.
      // child 只是包含一个Widget
      // 有些是children 可以包含多个Widget
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _getButtons(),
          Text("当前计数:$_counter",style:TextStyle(fontSize: 30))
        ],
      ),
    );
  }

  // 抽取方法 用于获取按钮
  Widget _getButtons() {
    
    
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        RaisedButton(
            child: Text("+",style: TextStyle(fontSize: 20,color: Colors.white)),
            color: Colors.pink,
            onPressed: () {
    
    
              // 刷新页面 状态更新
              setState(() {
    
    
                _counter++;
              });
         }
        ),
        RaisedButton(
            child: Text("-",style: TextStyle(fontSize: 20,color: Colors.white)),
            color: Colors.orange,
            onPressed: ()  {
    
    
                setState(() {
    
    
                _counter--;
                });
          }
        ),
      ],
    );

  }
}

2.2 效果图

请添加图片描述


③、Flutter的Widget生命周期

3.1 StatelessWidget生命周期

// StatelessWidget的生命周期
class YHiOSHomeContent extends StatelessWidget {
    
    
  final String message;

  YHiOSHomeContent(this.message){
    
    
    print("构造函数被调用");
  }
  @override
  Widget build(BuildContext context) {
    
    
    print("调用build方法");
    return Text(message);
  }
}

⭐️ 3.2 StatefulWidget生命周期

class YHiOSHomeContent extends StatefulWidget {
    
    

  YHiOSHomeContent(){
    
    
    print("1.调用了 YHiOSHomeContent 的 constructor方法");
  }
  @override
  _YHiOSHomeContentState createState() {
    
    
    print("2.调用了 YHiOSHomeContent 的 createState方法");
    return _YHiOSHomeContentState();
    }
}

class _YHiOSHomeContentState extends State<YHiOSHomeContent> {
    
    
  _YHiOSHomeContentState() {
    
    
    print("3.调用了 _YHiOSHomeContentState 的 constructor方法");

  }
  void initState(){
    
    
    // 调用: 这里是必须调用 super
    //
    super.initState();
    print("4.调用了 _YHiOSHomeContentState 的 initState方法");

  }
  @override
  Widget build(BuildContext context) {
    
    
    print("5.调用了 _YHiOSHomeContentState 的 build方法");
    return Container();
  }
  @override
  void dispose() {
    
    
    // TODO: implement dispose
    print("6.调用了 _YHiOSHomeContentState 的 dispose方法");

    super.dispose();
  }
}

3.3 为什么点击的时候 要调用 setState方法进行刷新

因为系统内部已经做了处理 只有调用setState方法之后 .才会重新build

请添加图片描述

setState方法原理案例 maiin.dart


import 'package:flutter/material.dart'; // runApp在这个material库里面
// 使用箭头函数
main() => runApp(MyApp());

// <stlss> 使用代码只能提示 快速创建一个继承与 StatelessWidget 的类

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    return MaterialApp(
      home:YHiOSHomePage() ,
    );
  }
}

class YHiOSHomePage extends StatelessWidget {
    
    
  const YHiOSHomePage({
    
    Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    
    
    // 主页 使用一个小组件 Scaffold
    return Scaffold(
      appBar: AppBar(
        title: Text("商品列表"),
      ),
      // body: YHiOSHomeContent("你好呀 宇夜iOS"),
      body: YHiOSHomeContent(),

    );
  }
}

// StatelessWidget的生命周期
// class YHiOSHomeContent extends StatelessWidget {
    
    
//   final String message;
//
//   YHiOSHomeContent(this.message){
    
    
//     print("构造函数被调用");
//   }
//   @override
//   Widget build(BuildContext context) {
    
    
//     print("调用build方法");
//     return Text(message);
//   }
// }


// StatefulWidget的生命周期

//
class YHiOSHomeContent extends StatefulWidget {
    
    

  YHiOSHomeContent(){
    
    
    print("1.调用了 YHiOSHomeContent 的 constructor方法");
  }
  @override
  _YHiOSHomeContentState createState() {
    
    
    print("2.调用了 YHiOSHomeContent 的 createState方法");
    return _YHiOSHomeContentState();
    }
}

class _YHiOSHomeContentState extends State<YHiOSHomeContent> {
    
    
  int _counter = 0;
  _YHiOSHomeContentState() {
    
    
    print("3.调用了 _YHiOSHomeContentState 的 constructor方法");

  }
  void initState(){
    
    
    // 调用: 这里是必须调用 super
    //
    super.initState();
    print("4.调用了 _YHiOSHomeContentState 的 initState方法");

  }
  @override
  Widget build(BuildContext context) {
    
    
    print("5.调用了 _YHiOSHomeContentState 的 build方法");
    return Column(
      children: [
        RaisedButton(
          child: Icon(Icons.add),
          onPressed: (){
    
    
            setState(() {
    
    
              _counter ++;
            });
          },
        ),
        Text("数字:$_counter")
      ],
    );
  }
  @override
  void dispose() {
    
    
    // TODO: implement dispose
    print("6.调用了 _YHiOSHomeContentState 的 dispose方法");

    super.dispose();
  }
}

猜你喜欢

转载自blog.csdn.net/qq_42816425/article/details/123372844