Flutter部件内部状态管理小结之实现Vue的v-model功能


Posted in Javascript onJune 11, 2019

Flutter部件内部状态管理

本文是 Flutter 部件内部状态管理的小结,从部件的基础开始,到部件的状态管理,并且在过程中实现一个类似 Vue 的 v-model 的功能。

widget 基础

widget(部件)

如 React 里万物皆组件, Java 里万物皆对象, Flutter 里,能看到的一切都是 widget(部件),如按钮、文本框等等。

Flutter 内部已经为我们做了一些基础的 widget ,例如:

  • Text : 这个就是一个文本部件,里面用于放置文本
  • Row , Column : 行列布局部件
  • Container : 可以理解为 HTML 里的 div

状态

状态可以理解为 widget 内拥有的成员变量

无状态 widget

无状态是指该成员变量不可改变,即使用 final 修饰符,为常量,创建无状态组件步骤如下:

创建一个类继承 StatelessWidget

实现 build 方法(类比写 HTML + CSS )

import 'package:flutter/material.dart';

class StateLessDemoWidget extends StatelessWidget {
 /// 如果定义非final修饰的成员变量,会提示
 /// This class (or a class which this class inherits from) is marked as '@immutable', but one or more of its instance fields are not final: StateLessDemoWidget.listInde
 /// int [listIndex];
 @override
 Widget build(BuildContext context) {
 return Container();
 }
}

有状态 widget

有状态则是指该 widget 内部的成员变量可以不使用 final 修饰符,并通过 setState() 方法改变成员变量的值时,引起 widget 的状态改变并重绘(例如文本框绑定变量A,通过改变变量A修改文本框的值,这里的变量A可以理解为可变状态)

有状态 widget 通过实现 StatefulWidget 和 State 两个子类实现,步骤如下:

  • 创建一个 Widget 类,继承 StatefulWidget
  • 创建一个继承 State 的类
  • 在 State 类里创建状态(成员变量),和实现 build 方法(画界面)
import 'package:flutter/material.dart';

/// 创建一个继承[StatefulWidget]的widget类
/// 这个类的效果类似收藏,有个空心的爱心图标
/// 点击一下爱心填充红色,再点击一次就取消填充
class FavoriteWidget extends StatefulWidget {
 @override
 _FavoriteWidgetState createState() => _FavoriteWidgetState();
}

/// [State]类,FavoriteWidget的具体实现
/// 包含一个状态[_isFavorited]
class _FavoriteWidgetState extends State<FavoriteWidget> {
 bool _isFavorited = true;

 @override
 Widget build(BuildContext context) {
 return Row(
 mainAxisSize: MainAxisSize.min,
 children: [
 Container(
 padding: EdgeInsets.all(0),
 child: IconButton(
 /// [_isFavorited] 为 true 时使用图标 Icons.star 否则使用 Icons.star_border
 icon: (_isFavorited ? Icon(Icons.star) : Icon(Icons.star_border)),

 color: Colors.red[500],

 /// 当点击时,改变状态
 onPressed: _toggleFavorite,
 ),
 ),
 ],
 );
 }

 /// 改变[_isFavorited]的状态
 void _toggleFavorite() {
 setState(() {
 if (_isFavorited) {
 _isFavorited = false;
 } else {
 _isFavorited = true;
 }
 });
 }
}

widget 管理内部状态的三种方式

widget 自己管理状态

其实和上边的 有状态部件 示例一样的,直接上代码

import 'package:flutter/material.dart';

class TapboxA extends StatefulWidget {
 @override
 _TapboxAState createState() => _TapboxAState();
}
/// [TapboxA]拥有状态[_active],通过[_handleTap]方法管理[_active]
class _TapboxAState extends State<TapboxA> {
 bool _active = false;

 void _handleTap() {
 setState(() {
 _active = !_active;
 });
 }
 Widget build(BuildContext context) {
 return GestureDetector(
 onTap: _handleTap,
 child: Center(
 child: Text(
 _active ? 'Active' : 'Inactive',
 ),
 ),
 );
 }
}

父widget 管理 子widget 状态

这一小节将实现一个和 Vue 的 v-model 一样的功能,父部件管理子部件的步骤如下:

  • 创建一个无状态部件作为子部件,构造函数中需要接收状态的值和状态改变时的回调函数
  • 创建一个有状态部件作为父部件,并定义需要管理的状态
  • 在父部件中创建子部件,并绑定状态和回调事件
import 'package:flutter/material.dart';

/// 父部件管理TapboxB的状态
///
/// 父部件[ParentWidget]定义了[_active]状态,并和[TapboxB]的[active]绑定
/// 当[TapboxB]被点击时,通过[onChanged]方法通知父部件,父部件修改[_active]的值
/// 也就间接修改了[TapboxB]的[active]
///
/// 如果了解过Vue的v-model原理的话比较好理解,其实这个和Vue的v-model一样的

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

class ParentWidget extends StatefulWidget {
 @override
 _ParentWidgetState createState() => _ParentWidgetState();
}

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

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

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

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

// 注意[TapboxB]是无状态部件,所有成员变量使用 final 修饰
class TapboxB extends StatelessWidget {
 // 必须传递onChanged,用于通知父部件
 TapboxB({Key key, this.active: false, @required this.onChanged})
 : super(key: key);
 final bool active;
 final ValueChanged<bool> onChanged;

 void _handleTap() {
 // 通知父部件修改 active 的值
 onChanged(!active);
 }

 Widget build(BuildContext context) {
 return GestureDetector(
 // 被点击时
 onTap: _handleTap,
 child: Center(
 child: Text(
 // active 改变时修改文本的内容
 active ? 'Active' : 'Inactive',
 ),
 ),
 );
 }
}

混合管理

在这种管理模式下,和父管理子部件的区别是,子部件也需要管理自己的状态,所以子部件也将是有状态部件(区别)。

步骤如下:

  1. 创建一个【有状态部件】作为子部件,构造函数中需要接收状态的值和状态改变时的回调函数
  2. 为子部件定义子部件内部的状态(多的一步)
  3. 创建一个有状态部件作为父部件,并定义需要管理的状态
  4. 在父部件中创建子部件,并绑定状态和回调事件
import 'package:flutter/material.dart';
//---------------------------- ParentWidget ----------------------------

class ParentWidget extends StatefulWidget {
 @override
 _ParentWidgetState createState() => _ParentWidgetState();
}

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

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

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

//----------------------------- TapboxC ------------------------------
class TapboxC extends StatefulWidget {
 TapboxC({Key key, this.active: false, @required this.onChanged})
 : super(key: key);

 final bool active;
 final ValueChanged<bool> onChanged;

 _TapboxCState createState() => _TapboxCState();
}

class _TapboxCState extends State<TapboxC> {
 /// [TapboxC]管理内部的边框是否高亮,通过状态[_highlight]来修改
 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);
 }

 Widget build(BuildContext context) {
 return GestureDetector(
 // onXXX都是事件处理
 onTapDown: _handleTapDown,
 onTapUp: _handleTapUp,
 onTap: _handleTap,
 onTapCancel: _handleTapCancel,
 child: Container(
 child: Center(
 child: Text(widget.active ? 'Active' : 'Inactive',
 style: TextStyle(fontSize: 32.0, color: Colors.white)),
 ),
 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,
 ),
 ),
 );
 }
}

总结

以上所述是小编给大家介绍的Flutter部件内部状态管理小结之实现Vue的v-model功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
js点击事件链接的问题解决
Apr 25 Javascript
js怎么覆盖原有方法实现重写
Sep 04 Javascript
js判断一个字符串是否包含一个子串的方法
Jan 26 Javascript
javascript用函数实现对象的方法
May 14 Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【一】
May 10 Javascript
再次谈论Javascript中的this
Jun 23 Javascript
JSON对象转化为字符串详解
Aug 11 Javascript
二维码图片生成器QRCode.js简单介绍
Aug 18 Javascript
基于jQuery实现无缝轮播与左右点击效果
May 13 jQuery
js实现按钮开关单机下拉菜单效果
Nov 22 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
May 30 Javascript
jquery html添加元素/删除元素操作实例详解
May 20 jQuery
JavaScript动态检测密码强度原理及实现方法详解
Jun 11 #Javascript
聊聊Vue 中 title 的动态修改问题
Jun 11 #Javascript
vue+element模态框中新增模态框和删除功能
Jun 11 #Javascript
vue.js中导出Excel表格的案例分析
Jun 11 #Javascript
ES6 Proxy实现Vue的变化检测问题
Jun 11 #Javascript
webpack实践之DLLPlugin 和 DLLReferencePlugin的使用教程
Jun 10 #Javascript
vue2 中二级路由高亮问题及配置方法
Jun 10 #Javascript
You might like
全国FM电台频率大全 - 7 吉林省
2020/03/11 无线电
php 删除记录实现代码
2009/03/12 PHP
php发送post请求函数分享
2014/03/06 PHP
yii2.0框架场景的简单使用示例
2020/01/25 PHP
php实现JWT验证的实例教程
2020/11/26 PHP
深入理解JavaScript系列(11) 执行上下文(Execution Contexts)
2012/01/15 Javascript
Prototype源码浅析 String部分(四)之补充
2012/01/16 Javascript
怎样在JavaScript里写一个swing把数据插入数据库
2012/12/10 Javascript
jQuery动画效果-slideUp slideDown上下滑动示例代码
2013/08/28 Javascript
Node.js编码规范
2014/07/14 Javascript
jQuery晃动层特效实现方法
2015/03/09 Javascript
js实现新浪微博首页效果
2015/10/16 Javascript
jQuery 选择器(61种)整理总结
2016/09/26 Javascript
js+div+css下拉导航菜单完整代码分享
2016/12/28 Javascript
jquery 校验中国身份证号码实例详解
2017/04/11 jQuery
浅谈JS获取元素的N种方法及其动静态讨论
2017/08/25 Javascript
seaJs使用心得之exports与module.exports的区别实例分析
2017/10/13 Javascript
node puppeteer(headless chrome)实现网站登录
2018/05/09 Javascript
Vue 路由 过渡动效 数据获取方法
2018/07/31 Javascript
重新认识vue之事件阻止冒泡的实现
2018/08/02 Javascript
详解mpvue中小程序自定义导航组件开发指南
2019/02/11 Javascript
Vue 实现一个命令式弹窗组件功能
2019/09/25 Javascript
react quill中图片上传由默认转成base64改成上传到服务器的方法
2019/10/30 Javascript
vue大型项目之分模块运行/打包的实现
2020/09/21 Javascript
Vue3+elementui plus创建项目的方法
2020/12/01 Vue.js
在Django的视图中使用数据库查询的方法
2015/07/16 Python
Python中条件判断语句的简单使用方法
2015/08/21 Python
python 连接sqlite及简单操作
2017/06/30 Python
Python中字典(dict)合并的四种方法总结
2017/08/10 Python
Pycharm设置去除显示的波浪线方法
2018/10/28 Python
Python列表切片常用操作实例解析
2020/03/10 Python
matplotlib.pyplot.matshow 矩阵可视化实例
2020/06/16 Python
详解Python3.8+PyQt5+pyqt5-tools+Pycharm配置详细教程
2020/11/02 Python
css3进行截取替代js的substring
2013/09/02 HTML / CSS
美国顶尖折扣时尚购物网:Bluefly
2016/08/28 全球购物
计划生育工作汇报
2014/10/28 职场文书