Flutter中mixin的使用详解
mixin是什么
mixin应该怎么理解呢,对Java系出身的我来说,这是一个新概念,各类资料的介绍也没找到一个清晰的定义。从个人理解来看,可以把它想象为Kotlin中的接口(和Java的区别是可以带非抽象的属性和方法),而多个mixin可以相互覆盖以实现组合,提供了非常大的灵活性,也可以达到类似多重继承的效果。
页表页面
这是一个普通的展示数据,上拉加载更多数据的列表。
其中有一个类型为List<T
的数据列表listData,有个page数据用于分页,isLoading用来判断是否正在加载数据,scrollController用于列表控制器
如果存在大量这种页面则可以用mixin来处理,不免大量重复的代码
import 'package:flutter/material.dart';
import 'package:flutter_app/app/model/ListViewJson.dart';
import 'package:flutter_app/app/shared/api/api.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'package:flutter_app/app/shared/mixins/list_more_data_mixin.dart';
/// 列表页面
class RecommendView extends StatefulWidget {
@override
_RecommendViewState createState() = _RecommendViewState();
}
class _RecommendViewState
extends ListMoreDataBase<ListViewJsonData, RecommendView
with ListMoreDataMixin<ListViewJsonData, RecommendView {
@override
Future<List<ListViewJsonData getData() async {
String data = await DioUtils.postHttp(
"api/getOneLevel",
parameters: FormData.fromMap({
'page': page,
'limit': '10',
}),
);
ListViewJson _json = ListViewJson.fromJson(json.decode(data));
return _json.data;
}
@override
void initState() {
print('init widget');
super.initState();
}
@override
void dispose() {
print('dispose widget');
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text('返回')),
body: Stack(
children: <Widget [
NotificationListener<ScrollNotification (
onNotification: onNotification,
child: ListView.builder(
controller: scrollController,
itemCount: listData.length,
itemBuilder: (BuildContext context, int index) =
TeamListItem(listData[index]),
),
),
isLoading ? Center(child: CircularProgressIndicator()) : Container()
],
),
);
}
}
mixin
import 'package:flutter/material.dart';
abstract class ListMoreDataBase<T, K extends StatefulWidget extends State<K {
/// 获取异步数据
Future<List<T getData();
}
/// 在
mixin ListMoreDataMixin<T, K extends StatefulWidget on ListMoreDataBase<T, K {
@override
void initState() {
print('init');
super.initState();
initData();
}
@override
void dispose() {
print('dispose');
super.dispose();
scrollController?.dispose();
}
/// 数据列表
List<T listData = [];
/// 分页
int page = 1;
/// 是否在加载数据
bool isLoading = false;
/// 滚动条控制器
ScrollController scrollController = ScrollController();
/// 初始化数据
Future<void initData() async {
setState(() {
isLoading = true;
});
List<T data = await getData();
if (!mounted) return;
setState(() {
listData = data;
isLoading = false;
});
}
/// 上拉加载更多
Future<void loadMore() async {
setState(() {
isLoading = true;
page += 1;
});
List<T data = await getData();
if (data.isEmpty) {
page--;
}
setState(() {
listData.addAll(data);
isLoading = false;
});
}
bool canLoadMore(ScrollNotification scroll) {
return !isLoading &&
scroll.metrics.maxScrollExtent <= scrollController.offset;
}
bool onNotification(ScrollNotification scroll) {
if (canLoadMore(scroll)) {
loadMore();
}
return true;
}
}
注:
- dart是单继承
- 在类中,能重写mixin的属性和方法,并且也能用super调用miixn属性和方法
- 上面的生命周期依次打印 init widget – init – dispose widget – dispose
ps:下面从简单到复杂,演示mixin在Dart中的用法
最简单的mixin
mixin TestMixin {
void test() {
print('test');
}
int testInt = 1;
void test2();
}
class Test with TestMixin {
@override
test2() {
print('test2');
}
}
void main() {
Test().test(); // test
print(Test().testInt); // 1
Test().test2(); // test2
}
mixin本身可以是抽象的,可以定义各种方法属性,也可以是抽象的,等后续类去实现
基于某个类型的mixin
class BaseObject {
void method() {
print('call method');
}
}
mixin TestMixin on BaseObject{
void test() {
print('test');
}
int testInt = 1;
void test2() {
method();
}
}
class Test extends BaseObject with TestMixin {
}
void main() {
Test().test(); // test
print(Test().testInt); // 1
Test().test2(); // call method
}
当使用on关键字,则表示该mixin只能在那个类的子类使用了,那么结果显然的,mixin中可以调用那个类定义的方法、属性
多个mixin
mixin TestMixin {
void test() {
print('test');
}
int testInt = 1;
void test2();
}
mixin TestMixin2 {
int testInt = 2;
void test3() {
print('test3');
}
}
class Test with TestMixin, TestMixin2 {
@override
test2() {
print('test2');
}
}
void main() {
Test().test(); // test
print(Test().testInt); // 2
Test().test2(); // test2
Test().test3(); // test3
}
如果把TestMixin和TestMixin2的先后顺序改一下:
mixin TestMixin {
void test() {
print('test');
}
int testInt = 1;
void test2();
}
mixin TestMixin2 {
int testInt = 2;
void test3() {
print('test3');
}
}
class Test with TestMixin2, TestMixin {
@override
test2() {
print('test2');
}
}
void main() {
Test().test(); // test
print(Test().testInt); // 1
Test().test2(); // test2
Test().test3(); // test3
}
如果mixin存在冲突的部分,后面会覆盖前面的,没有冲突的则会保留,所以可以存在后面的mixin修改了前面的mixin的一部分逻辑的情况,不需要直接继承即可实现覆盖,避免了更复杂的继承关系
"多重继承"
mixin TestMixin on BaseClass {
void init() {
print('TestMixin init start');
super.init();
print('TestMixin init end');
}
}
mixin TestMixin2 on BaseClass {
void init() {
print('TestMixin2 init start');
super.init();
print('TestMixin2 init end');
}
}
class BaseClass {
void init() {
print('Base init');
}
BaseClass() {
init();
}
}
class TestClass extends BaseClass with TestMixin, TestMixin2 {
@override
void init() {
print('TestClass init start');
super.init();
print('TestClass init end');
}
}
void main() {
TestClass();
/// TestClass init start
/// TestMixin2 init start
/// TestMixin init start
/// Base init
/// TestMixin init end
/// TestMixin2 init end
/// TestClass init end
}
稍微有点绕,可以看到,这已经事实上达到多重继承才能达到的效果了,写起来比较麻烦,某种程度上也更不容易出错(相对于C++)。。。源码里有最好也最复杂的例子—WidgetsFlutterBinding,它的定义如下:
class WidgetsFlutterBinding
extends BindingBase with GestureBinding,
ServicesBinding,
SchedulerBinding,
PaintingBinding,
SemanticsBinding,
RendererBinding,
WidgetsBinding
{
}
具体WidgetsFlutterBinding的分析就没啦,自己看源码去吧~~
总结
到此这篇关于Flutter中mixin的使用的文章就介绍到这了,更多相关flutter mixin使用内容请搜索ZaLou.Cn以前的文章或继续浏览下面的相关文章希望大家以后多多支持ZaLou.Cn!
- IBatisNet之获取和操作SQL语句
- 大数据研究学者谈城市运行安全:要将应急处置转化为风险管理
- Castle.MVC框架介绍
- 在 .Net 设定 proxy 的方法
- MVC结构简介
- 优酷、爱奇艺、摩拜……多家网络平台被曝注册容易注销难!面临个人隐私泄露风险
- WordPress中借助.htaccess屏蔽某个IP或某个IP段(防垃圾评论)
- ASP.NET 调味品:AJAX
- CTreeCtrl 控件使用总结
- 高盛成立交易部门,涉足比特币和加密货币交易
- WordPress主题开发:添加主题更新提醒功能
- WordPress主题开发:添加主题更新提醒功能
- ASP.NET2.0应用中定制安全凭证之实践篇
- Kaggle大神带你上榜单Top2%:点击预测大赛纪实(下)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 内置函数值 -- chr() ord() -- 字符和ascii的转换
- python内置函数-compile()
- 02 . Shell变量和逻辑判断及循环使用
- Python内置函数(21)——filter
- 内置函数 -- filter 和 map
- 内置函数--global() 和 local()
- python file文件操作--内置对象open
- 07 . Prometheus监控Memcached并配置Grafana
- 内置函数 -- bytes -- 字节码与字符串相互转换
- 01 . Shell详细入门介绍及简单应用
- 06 . Prometheus监控Redis并配置Grafana
- Django实现图片上传并前端页面显示
- 04 . Prometheus(联邦集群)监控MySQL
- 01 . MongoDB简介及部署配置
- 06 . Jenkins分布式构建和Pipline