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 相关文章推荐
jMessageBox 基于jQuery的窗口插件
Dec 09 Javascript
node.js中格式化数字增加千位符的几种方法
Jul 03 Javascript
JS组件中bootstrap multiselect两大组件较量
Jan 26 Javascript
基于JavaScript实现带缩略图的轮播效果
Jan 12 Javascript
JavaScript实现form表单的多文件上传
Mar 27 Javascript
vue2.0使用swiper组件实现轮播效果
Nov 27 Javascript
原生js实现公告滚动效果
Jan 10 Javascript
layer ui插件显示tips时,修改字体颜色的实现方法
Sep 11 Javascript
vue中nextTick用法实例
Sep 11 Javascript
微信小程序停止其他视频播放当前视频的实例代码
Dec 25 Javascript
使用 Vue-TCB 快速在 Vue 应用中接入云开发的方法
Feb 10 Javascript
JS实现打砖块游戏
Feb 14 Javascript
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
PHP脚本的10个技巧(6)
2006/10/09 PHP
php读取大文件示例分享(文件操作类)
2014/04/13 PHP
使用PHP把HTML生成PDF文件的几个开源项目介绍
2014/11/17 PHP
9条PHP编程小知识及易犯的小错误
2015/01/22 PHP
Ext.MessageBox工具类简介
2009/12/10 Javascript
游览器中javascript的执行过程(图文)
2012/05/20 Javascript
window.addEventListener来解决让一个js事件执行多个函数
2012/12/26 Javascript
JavaScript实现自动对页面上敏感词进行屏蔽的方法
2015/07/27 Javascript
JS本地刷新返回上一页代码
2016/07/25 Javascript
浅谈Javascript数据属性与访问器属性
2016/07/26 Javascript
AngularJS入门教程之控制器详解
2016/07/27 Javascript
给easyui的datebox控件添加清空按钮的实现方法
2016/11/09 Javascript
JS实现全屏的四种写法
2016/12/30 Javascript
Node.JS利用PhantomJs抓取网页入门教程
2017/05/19 Javascript
JavaScript去掉数组重复项的方法分析【测试可用】
2018/07/19 Javascript
vue项目中使用Hbuilder打包app 设置沉浸式状态栏的方法
2018/10/22 Javascript
Vue如何跨组件传递Slot的实现
2020/12/14 Vue.js
[01:19:23]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第二场
2018/04/06 DOTA
初学python数组的处理代码
2011/01/04 Python
浅谈python中scipy.misc.logsumexp函数的运用场景
2016/06/23 Python
Python模拟用户登录验证
2017/09/11 Python
基于python 二维数组及画图的实例详解
2018/04/03 Python
Python不同目录间进行模块调用的实现方法
2019/01/29 Python
python多线程使用方法实例详解
2019/12/30 Python
3种python调用其他脚本的方法
2020/01/06 Python
TensorFLow 不同大小图片的TFrecords存取实例
2020/01/20 Python
python实现猜拳游戏项目
2020/11/30 Python
CSS3中新增的对文本和字体的设置
2020/02/03 HTML / CSS
加拿大快时尚零售商:Ardene
2018/02/14 全球购物
师范大学毕业自我鉴定
2013/11/21 职场文书
电脑租赁公司创业计划书
2014/01/08 职场文书
感恩节活动策划方案
2014/05/16 职场文书
马丁路德金演讲稿
2014/05/19 职场文书
2014年秋季新学期寄语
2014/08/02 职场文书
学习党章的体会
2014/11/07 职场文书
高中英语教学反思范文
2016/03/02 职场文书