Flutter中mixin的使用詳解
mixin是什么
mixin應(yīng)該怎么理解呢,對(duì)Java系出身的我來(lái)說(shuō),這是一個(gè)新概念,各類資料的介紹也沒(méi)找到一個(gè)清晰的定義。從個(gè)人理解來(lái)看,可以把它想象為Kotlin中的接口(和Java的區(qū)別是可以帶非抽象的屬性和方法),而多個(gè)mixin可以相互覆蓋以實(shí)現(xiàn)組合,提供了非常大的靈活性,也可以達(dá)到類似多重繼承的效果。
頁(yè)表頁(yè)面
這是一個(gè)普通的展示數(shù)據(jù),上拉加載更多數(shù)據(jù)的列表。
其中有一個(gè)類型為List<T>的數(shù)據(jù)列表listData,有個(gè)page數(shù)據(jù)用于分頁(yè),isLoading用來(lái)判斷是否正在加載數(shù)據(jù),scrollController用于列表控制器
如果存在大量這種頁(yè)面則可以用mixin來(lái)處理,不免大量重復(fù)的代碼
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';
/// 列表頁(yè)面
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> {
/// 獲取異步數(shù)據(jù)
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();
}
/// 數(shù)據(jù)列表
List<T> listData = [];
/// 分頁(yè)
int page = 1;
/// 是否在加載數(shù)據(jù)
bool isLoading = false;
/// 滾動(dòng)條控制器
ScrollController scrollController = ScrollController();
/// 初始化數(shù)據(jù)
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調(diào)用miixn屬性和方法
- 上面的生命周期依次打印 init widget -> init -> dispose widget -> dispose
ps:下面從簡(jiǎn)單到復(fù)雜,演示mixin在Dart中的用法
最簡(jiǎn)單的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本身可以是抽象的,可以定義各種方法屬性,也可以是抽象的,等后續(xù)類去實(shí)現(xiàn)
基于某個(gè)類型的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
}
當(dāng)使用on關(guān)鍵字,則表示該mixin只能在那個(gè)類的子類使用了,那么結(jié)果顯然的,mixin中可以調(diào)用那個(gè)類定義的方法、屬性
多個(gè)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存在沖突的部分,后面會(huì)覆蓋前面的,沒(méi)有沖突的則會(huì)保留,所以可以存在后面的mixin修改了前面的mixin的一部分邏輯的情況,不需要直接繼承即可實(shí)現(xiàn)覆蓋,避免了更復(fù)雜的繼承關(guān)系
"多重繼承"
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
}
稍微有點(diǎn)繞,可以看到,這已經(jīng)事實(shí)上達(dá)到多重繼承才能達(dá)到的效果了,寫起來(lái)比較麻煩,某種程度上也更不容易出錯(cuò)(相對(duì)于C++)。。。源碼里有最好也最復(fù)雜的例子—WidgetsFlutterBinding,它的定義如下:
class WidgetsFlutterBinding
extends BindingBase with GestureBinding,
ServicesBinding,
SchedulerBinding,
PaintingBinding,
SemanticsBinding,
RendererBinding,
WidgetsBinding
{
}
具體WidgetsFlutterBinding的分析就沒(méi)啦,自己看源碼去吧~~
總結(jié)
到此這篇關(guān)于Flutter中mixin的使用的文章就介紹到這了,更多相關(guān)flutter mixin使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中實(shí)現(xiàn)延時(shí)執(zhí)行操作的方法小結(jié)
在Android開發(fā)中我們可能會(huì)有延時(shí)執(zhí)行某個(gè)操作的需求,這篇文章主要介紹了Android中實(shí)現(xiàn)延時(shí)執(zhí)行操作的幾種方法,需要的朋友可以參考下2018-10-10
Android中webView加載H5綁定cookie實(shí)例
這篇文章主要介紹了Android中webView加載H5綁定cookie實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android webView如何輸出自定義網(wǎng)頁(yè)
這篇文章主要介紹了Android webView如何輸出自定義網(wǎng)頁(yè),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Android中g(shù)son、jsonobject解析JSON的方法詳解
JSON即JavaScript Object Natation, 它是一種輕量級(jí)的數(shù)據(jù)交換格式, 與XML一樣, 是廣泛被采用的客戶端和服務(wù)端交互的解決方案.接下來(lái)由腳本之家小編給大家介紹Android中g(shù)son、jsonobject解析JSON的方法,感興趣的朋友一起學(xué)習(xí)吧2016-02-02
Android進(jìn)程間大數(shù)據(jù)通信LocalSocket詳解
這篇文章主要為大家介紹了Android進(jìn)程間大數(shù)據(jù)通信LocalSocket詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Android recycleView的應(yīng)用和點(diǎn)擊事件實(shí)例詳解
這篇文章主要介紹了Android recycleView的應(yīng)用和點(diǎn)擊事件實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12

