Flutter中将自己写的通用Widget抽离出来成为一个Package
- package是什么?怎么创建一个package?
- 为什么要抽离出来为一个package?
- 怎么实现?
关于Package
Package可以理解为插件(plugin),但插件只是package的一种,也就是说package包含于插件又不只是插件。写Flutter项目时,不可避免的使用到不同的package,也就引用的其他第三方库。在Flutter中引入方式为在项目目录下的pubspec.yaml文件中,dependencies下,如图:
如何创建一个package项目呢?
第一种方式是使用命令行
flutter create --template=package hello
第二种方式是使用Android studio创建,方式为:
- File-New-New Flutter Project
- 在弹出的New Project弹框点击Next-在Project type这一选项注意要修改为Package,然后点击Finish
- 注意:有的Android Studio会没有New Flutter Project这一选项,解决方式为:双击Shitft(Windows)-在弹出框中输入
AndroidApkSupport
,然后开启这个开关,重启Android Studio就好了。
解决方式出处:Android Studio 无法新建Flutter项目
为什么要抽离出来为一个Package?
我理解有一下几点:
- 将本地项目中一些通用的Widget抽离出来后,可以减少本地代码量;
- 以后其他项目如果也用到这个,直接在dependencies引用就可以了,更加方便;
- 可以上传到pub.dev可以供其他人使用;
实现步骤
例如一个loading加载框,代码如下:
import 'package:flutter/material.dart';
import 'package:linker_merchant/common/router.dart';
class LoadingDialog extends Dialog {
final String text;
LoadingDialog({this.text, Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
type: MaterialType.transparency,
child: GestureDetector(
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.transparent,
child: Center(
child: SizedBox(
width: 120.0,
height: 120.0,
child: Container(
decoration: const ShapeDecoration(
color: Color(0xffffffff),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const CircularProgressIndicator(),
Padding(
padding: const EdgeInsets.only(
top: 20.0,
),
child: Text(
text,
style: const TextStyle(fontSize: 12.0),
),
),
],
),
),
),
),
),
onTap: () {
Future.delayed(const Duration(seconds: 1), () {
LoadingDialogShow.dismissLoading();
});
},
),
);
}
}
class LoadingDialogShow {
static bool _isPerformingRefresh = false;
static showRefreshDataLoading() {
if (!_isPerformingRefresh) {
_isPerformingRefresh = true;
showDialog(
context: RouterConfig.navigatorKey.currentContext,
barrierDismissible: false,
builder: (context) {
return WillPopScope(
onWillPop: () async => false,
child: LoadingDialog(text: 'loading...'),
);
});
}
}
static dismissLoading() {
BuildContext context = RouterConfig.navigatorKey.currentContext;
if (_isPerformingRefresh) {
_isPerformingRefresh = false;
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
}
}
}
通过前面的方法,我们已经创建好了一个package项目,现在将这个类复制到package的lib目录下,然后创建一个Flutter Project命名为test_project,来测试一下是否可行。
在test_project中引用可以有两种方式,一种本地引用,也就是这个loading package还没有上传到远程仓库,只是在本地,引入方式如下:
loading_dialog为我们创建的这个package名称,path后面是文件的本地路径(绝对路径或相对路径都行,我这里使用的是绝对路径)。
另外一种方式是通过url引用,也就是package上传到远程仓库后的引用方式,引用方式如下:
url是这个package上传的远程仓库地址
ref是当前分支名称(如果不写ref这一项就默认为master分支)