首页 > 其他分享 >第142期:flutter的状态组件和状态管理

第142期:flutter的状态组件和状态管理

时间:2022-12-31 10:31:45浏览次数:41  
标签:状态 142 active State child 组件 const flutter

封面图

第142期:flutter的状态组件和状态管理_ide

我们在看电影的时候,往往只关注某个主演的角色,其实那些小角色的表演,远远比主演角色的表演要丰富~

场景

怎样才能在我们的flutter应用中对用户输入做出响应?比如我们有个图标,我们想让它支持点击事件,或者在状态改变的时候换一个不同的图标。

其实我们可以创建一个有状态的组件来控制或管理那些需要变化的组件。

状态组件 VS 无状态组件

这两个概念在react中我们非常熟悉,状态组件内部定义的有自己的属性,可以用来控制不同状态下展示不同的界面。无状态组件则只负责展示界面,没有其他的多余功能。

在flutter中无状态组件有很多,比如:​​Icon​​, ​​IconButton​​, and ​​Text​​。他们继承​​StatelessWidget​​类。

状态组件​​stateful widget​​​则是动态的:例如,它可以响应用户交互触发的事件或接收数据时更改其外观。​​Checkbox​​, ​​Radio​​, ​​Slider​​, ​​InkWell​​, ​​Form​​, and ​​TextField​​其实都是状态组件,他们继承了​​StateulWidget​​类。

回想一下web端的开发,其实大同小异。

组件的状态存储在state对象中,将控件的状态与其外观分开。状态由可以更改的值组成,例如滑块的当前值或是否选中复选框。当小部件的状态发生变化时,状态对象调用setState(),告诉框架重新绘制小部件。

创建状态组件

需要注意的是:

/**
1. 状态组件件由两个类实现:StatefulWidget的子类和State的子类。
2. state类包含组件的可变状态和组件的build()方法。
3. 当组件状态发生变化时,state对象调用setstate方法,通知框架重新绘制组件。
**/

创建一个自定义的状态组件需要创建两个类:

/**
1. StatefulWidget类 用来定义组件。
2. 包含组件状态的State类, 用来定义组件的build方法。
**/

先继承​​StatefulWidget​​类,定义组件:

class FavoriteWidget extends StatefulWidget {
const FavoriteWidget({super.key});

@override
State<FavoriteWidget> createState() => _FavoriteWidgetState();
}

再扩展​​State​​类定义状态:

class _FavoriteWidgetState extends State<FavoriteWidget> {
bool _isFavorited = true;
int _favoriteCount = 41;

// ···
}

然后实现​​build()​​方法实现组件展示:

class _FavoriteWidgetState extends State<FavoriteWidget> {
// ···
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(0),
child: IconButton(
padding: const EdgeInsets.all(0),
alignment: Alignment.centerRight,
icon: (_isFavorited
? const Icon(Icons.star)
: const Icon(Icons.star_border)),
color: Colors.red[500],
onPressed: _toggleFavorite,
),
),
SizedBox(
width: 18,
child: SizedBox(
child: Text('$_favoriteCount'),
),
),
],
);
}
}

然后实现​​ _toggleFavorite​​方法用来更新状态:

void _toggleFavorite() {
setState(() {
if (_isFavorited) {
_favoriteCount -= 1;
_isFavorited = false;
} else {
_favoriteCount += 1;
_isFavorited = true;
}
});
}

这样就简单的实现了一个状态组件。

状态管理

需要注意的内容:

/**
1. 管理状态有不同的方法。
2. 作为组件的开发者,我们可以选择具体使用哪种方法。
3. 如果我们不确定怎么管理状态,就把状态放到父组件中进行管理。
**/

到底是谁在负责状态的管理呢?组件本身?父组件?或者有个更高级的组件?其实是根据情况而定的。

根据实际情况进行状态管理是一种最有效的方法,以下是管理状态的最常见方法:

  • 组件自身控制自己的状态
  • 父组件控制子组件的状态
  • 混合状态控制

​我们该怎么选择呢?​​建议如下:

/**
1. 如果所讨论的状态是用户数据,例如复选框的选中或未选中模式,或者滑块的位置,那么状态最好由父组件管理。
2. 如果所讨论的状态是美学的,例如动画,那么状态最好由组件自身管理。
**/

组件管理自己的状态

有时候,组件在内部管理自己状态比较好。例如,当​​ListView​​​的内容超过渲染框时,它会自动滚动。大多数使用ListView的开发人员不想管理ListView的滚动行为,所以就让​​ListView​​本身管理其滚动偏移量。

举个例子,看下面的代码:

import 'package:flutter/material.dart';

// TapboxA manages its own state.

//------------------------- TapboxA ----------------------------------

class TapboxA extends StatefulWidget {
const TapboxA({super.key});

@override
State<TapboxA> createState() => _TapboxAState();
}

class _TapboxAState extends State<TapboxA> {
bool _active = false;

void _handleTap() {
setState(() {
_active = !_active;
});
}

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
child: Container(
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: _active ? Colors.lightGreen[700] : Colors.grey[600],
),
child: Center(
child: Text(
_active ? 'Active' : 'Inactive',
style: const TextStyle(fontSize: 32.0, color: Colors.white),
),
),
),
);
}
}

//------------------------- MyApp ----------------------------------

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: const Center(
child: TapboxA(),
),
),
);
}
}
  • 组件​​TapboxA​​​管理自己的状态​​_active​
  • 状态​​_active​​用来控制组件的颜色
  • ​_handleTap​​​方法调用​​setState​​来更新组件的展示

父组件管理状态

通常情况下,父组件管理状态并通知其子组件何时更新是最有意义的。例如,​​IconButton​​​可以让图标看作是可点击的按钮。​​IconButton​​是一个无状态的小部件,因为我们可以让父组件知道按钮是否被点击,以便采取适当的操作。

看下面的代码:

import 'package:flutter/material.dart';

// ParentWidget manages the state for TapboxB.

//------------------------ ParentWidget --------------------------------

class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});

@override
State<ParentWidget> createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;

void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}

@override
Widget build(BuildContext context) {
return SizedBox(
child: TapboxB(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}

//------------------------- TapboxB ----------------------------------

class TapboxB extends StatelessWidget {
const TapboxB({
super.key,
this.active = false,
required this.onChanged,
});

final bool active;
final ValueChanged<bool> onChanged;

void _handleTap() {
onChanged(!active);
}

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
child: Container(
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: active ? Colors.lightGreen[700] : Colors.grey[600],
),
child: Center(
child: Text(
active ? 'Active' : 'Inactive',
style: const TextStyle(fontSize: 32.0, color: Colors.white),
),
),
),
);
}
}
  • 父组件定义了状态​​_active​​​用来控制组件​​TapboxB​​的展示
  • 父组件定义了​​_handleTapboxChanged​​​,当组件​​TapboxB​​​被点击的时候会更新​​_active​
  • 子组件​​TapboxB​​​接受​​active​​​属性,同时定义了​​onChanged​​​属性方法,当点击子组件​​TapboxB​​​时,会触发父组件的​​_handleTapboxChanged​​方法,通知父组件,从而实现组件的更新。

混合状态管理

对于其他的一些组件件,混合使用混合状态管理最有意义。在这个场景中,状态组件管理自己的一些状态,而父组件管理状态的其他方面。

看下面的代码:

import 'package:flutter/material.dart';

//---------------------------- ParentWidget ----------------------------

class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});

@override
State<ParentWidget> createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;

void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}

@override
Widget build(BuildContext context) {
return SizedBox(
child: TapboxC(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}

//----------------------------- TapboxC ------------------------------

class TapboxC extends StatefulWidget {
const TapboxC({
super.key,
this.active = false,
required this.onChanged,
});

final bool active;
final ValueChanged<bool> onChanged;

@override
State<TapboxC> createState() => _TapboxCState();
}

class _TapboxCState extends State<TapboxC> {
bool _highlight = false;

void _handleTapDown(TapDownDetails details) {
setState(() {
_highlight = true;
});
}

void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}

void _handleTapCancel() {
setState(() {
_highlight = false;
});
}

void _handleTap() {
widget.onChanged(!widget.active);
}

@override
Widget build(BuildContext context) {
// This example adds a green border on tap down.
// On tap up, the square changes to the opposite state.
return GestureDetector(
onTapDown: _handleTapDown, // Handle the tap events in the order that
onTapUp: _handleTapUp, // they occur: down, up, tap, cancel
onTap: _handleTap,
onTapCancel: _handleTapCancel,
child: Container(
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
border: _highlight
? Border.all(
color: Colors.teal[700]!,
width: 10.0,
)
: null,
),
child: Center(
child: Text(widget.active ? 'Active' : 'Inactive',
style: const TextStyle(fontSize: 32.0, color: Colors.white)),
),
),
);
}
}

在这个示例中,按下时,框周围会出现一个深绿色边框。松手时,边框消失,框的颜色改变。组件​​TapboxC​​​将其活动状态导出到其父组件,但在自身内部管理其高亮状态。此示例有两个​​State​​​对象,​​_ParentWidgetState​​​和​​_TapboxCState​​。

​_ParentWidgetState​​对象:

  • 管理活动状态​​_active​​。
  • 实现了​​_handleTapboxChanged()​​方法,即在轻敲框时调用的方法。
  • 调用​​setState()​​​以在轻敲发生且​​_active​​状态更改时更新UI。

​_TapboxCState​​对象:

  • 管理自身状态​​_highlight​​。
  • ​GestureDetector​​​组件监听​​onTapDown​​和​​onTapUp​​事件。​​onTapDown​​时,它会添加高亮显示(实现为深绿色边框)。​​onTapUp​​时,它会删除高亮显示。
  • 在​​onTapDown​​和​​onTapUp​​调用​​setState()​​方法更新UI,并且​​_higlight​​状态发生变化。
  • 在​​_handleTap​​时,将状态传递到付组件中,通知父组件进行更新。

最后

在组件的状态管理中,我们使用的最多的交互场景大抵是表单相关的内容,相关的组件有:

  • Form
  • FormField
  • Checkbox
  • DropdowmButton
  • TextButton
  • FloatingActionButton
  • IconButton
  • Radio
  • ElevateButton
  • Slider
  • Switch
  • TextField
  • ...

和web开发使用的场景差不多~

我们在进行组件的封装时,本质上是在开发一个自定义的状态组件~

ps:

我正在参加年度气人作者榜的投票~
但是我没他们的票多~
我想变的更气人~
你们能帮帮我吗~
让我变的更气人~

​​掘金年度气人作者打榜~​​

标签:状态,142,active,State,child,组件,const,flutter
From: https://blog.51cto.com/u_15531399/5982010

相关文章

  • Zabbix监控Nginx性能状态
    Zabbix监控Nginx性能状态Nginx在生产环境中的应用越来越广泛,所以需要对nginx的性能状态做一些监控,从而发现故障隐患,Ngnx的监控指标可分为:基本活动指标,错误指标,性能指标。需......
  • Zabbix监控Redis性能状态
    Zabbix监控Redis性能状态监控原理示意图:监控原理Zabbix-server通过agent监控中配置文件调用shell脚本。Redis中提供redis-cli命令使用info可以获得redis大部分信息。在使用......
  • Zabbix监控MongoDB性能状态
    Zabbix监控MongoDB性能的原理:通过echo"db.serverStatus()"|mongoadmin来查看mongodb的状态。Zabbix监控MongoDB性能,主要监控以下项目:-内存使用情况-连接数-锁-刷新......
  • Flutter异常监控 - 贰 | 框架Catcher原理分析
    前言在给Flutter应用做异常监控的时候,一开始我是拒绝滴,如果不考虑FlutterEngine和native侧的监控,用我另一篇文章中不得不知道的Flutter异常捕获知识点提到的方......
  • 2、任务状态理论和实验
    一、任务状态理论:1、running2、ready3、blocked:阻塞,等待某件事情发生4、suspended:暂停(主动休息、被动休息)   纠正:应该是让任务3进入ready状态。   调用......
  • 为有状态应用而生,云原生本地存储Carina正式进入CNCF沙箱
    12月14日,云原生本地存储开源项目 Carina 通过了全球顶级开源基金会 CNCF技术监督委员会(TOC)的评定,正式成为CNCF沙箱级项目(SandboxProjects)。Carina是由博云于2021年10......
  • http状态码
    一、什么是状态码HTTP状态码(HTTPStatusCode)是用以表示网页服务器HTTP响应状态的3位数字代码。它由RFC2616规范定义的,并得到RFC2518、RFC2817、RFC2295、RFC2774、......
  • apache cv2.xxx(imread)方法一直挂起,处于堵塞状态,无法正常进行,
    flask项目中调用cv2.imread(),在flaskrun运行时一切正常,但是把flask项目部署到apache后cv2.imread()方法一直挂起,无法执行,导致处于堵塞状态,后来在网上查询解决,在httpd.conf......
  • ztree点击文字,实现复选框的选中状态
    在设置树的时候加上下面这句就好了  callback:{onClick:function(e,treeId,treeNode,clickFlag){vartreeObj=$.fn.zTree.getZTreeObj("r......
  • Miro Samek-状态机建模和实现-UMLChina讲座-音频和幻灯
    时间2010年6月27日(周日)晚上19:00-21:00演讲人MiroSamek博士,QuantumLeaps公司总裁,《PracticalUMLStatechartsinC/C++》作者。长期从事嵌入式软件开发,曾就职于GEHealth......