【Flutter】之便于提高开发效率的周边库和轮子
前言
GetX
状态管理
GetX包含很多功能,各种弹出widget、路由管理、国际化、Utils、状态管理等。
基于路由管理
1. 添加到项目中
1.1. 将此添加到pubspec.yaml文件中。
get: 4.1.4
1.2. 在命令行中运行
flutter packages get
1.3. 在MaterialApp前面加上 “Get”,就可以把它变成GetMaterialApp
GetMaterialApp(
home: MyHome(),
)
2. 具体的路由使用场景:
2.1 导航到新的页面。
Get.to(NextScreen());
2.2 关闭SnackBars、Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西。
Get.back();
2.3进入下一个页面,但没有返回上一个页面的选项(用于SplashScreens,登录页面等)。
Get.off(NextScreen());
2.4 进入下一个界面并取消之前的所有路由(在购物车、投票和测试中很有用)。
Get.offAll(NextScreen());
2.5 要导航到下一条路由,并在返回后立即接收或更新数据。
var data = await Get.to(Payment());
2.6 在另一个页面上,发送前一个路由的数据。并使用它,例:
Get.back(result: 'success');
if(data == 'success') madeAnything();
2.7 与标准导航的关系 , 只要把 Navigator(大写)改成 navigator(小写),就可以拥有标准导航的所有功能,而不需要使用context // 默认的Flutter导航
Navigator.of(context).push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return HomePage();
},
),
);
// 使用Flutter语法获得,而不需要context。
navigator.push(
MaterialPageRoute(
builder: (_) {
return HomePage();
},
),
);
// get语法 (这要好得多)
Get.to(HomePage());
dio:http 请求库
dio
是一个强大的Dart
Http
请求库,支持Restful API、FormData
、拦截器、请求取消、Cookie
管理、文件上传/下载、超时、自定义适配器等...
1. 添加到项目中
1.1. 将此添加到pubspec.yaml文件中。
dio: ^4.0.6
dio_cookie_manager: ^2.0.0
cookie_jar: ^3.0.1
1.2. 在命令行中运行
flutter packages get
2.具体的使用
一个极简的示例:
import 'package:dio/dio.dart';
void getHttp() async {
try {
var response = await Dio().get('http://www.google.com');
print(response);
} catch (e) {
print(e);
}
}
项目中的使用:
config.dart
统一管理请求接口的
url
地址
// api地址前缀
static String imApiUrl() {
return 'https://xxxxxx.xxxxx.com/api/users';
}
// 接口列表
class Urls {
static var register = "${Config.imApiUrl()}/register";
static var login = "${Config.imApiUrl()}/login";
static var getCode = "${Config.imApiUrl()}/getCode";
static var verifiCode = "${Config.imApiUrl()}/verifiCode";
static var setNewPwd = "${Config.imApiUrl()}/setNewPwd";
}
api_resp.dart
对接口返回的数据,进行统一数据类型校验
class ApiResp {
int? code;
String? msg;
dynamic data;
ApiResp.fromJson(Map<String, dynamic> map) {
code = map["code"];
msg = map["msg"];
data = map["data"] ?? {};
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['code'] = code;
data['msg'] = msg;
data['data'] = data;
return data;
}
}
api_interceptor.dart
对于请求的拦截
import 'package:dio/dio.dart';
import 'config.dart';
import 'api_resp.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
Dio dio = Dio();
class HttpUtil {
HttpUtil._();
static void init() {
dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
return handler.next(options);
}, onResponse: (response, handler) {
return handler.next(response);
}, onError: (DioError e, handler) {
return handler.next(e);
}));
dio.interceptors.add(CookieManager(CookieJar()));
// 配置dio实例
dio.options.baseUrl = Config.imApiUrl();
dio.options.connectTimeout = 30000;
dio.options.receiveTimeout = 30000;
}
// post 请求
static Future<Map<String, dynamic>> post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
try {
var result = await dio.post<Map<String, dynamic>>(
path,
data: data,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
print(result);
var resp = ApiResp.fromJson(result.data!);
// 成功返回
if (resp.code == 0) {
var response = {"data": resp.data, "code": resp.code, "msg": resp.msg};
return response;
} else {
// 业务报错
return Future.error((resp.msg).toString());
}
} catch (error) {
// 网络报错
if (error is DioError) {
} else {}
return Future.error(error);
}
}
// get请求
static Future<Map<String, dynamic>> get(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
CancelToken? cancelToken,
ProgressCallback? onReceiveProgress,
}) async {
try {
var result = await dio.get<Map<String, dynamic>>(
path,
queryParameters: queryParameters,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress,
);
var resp = ApiResp.fromJson(result.data!);
// 成功返回
if (resp.code == 0) {
var response = {
"data": resp.data ?? {},
"code": resp.code,
"msg": resp.msg
};
return response;
} else {
// 业务报错
return Future.error(resp);
}
} catch (error) {
// 网络报错
if (error is DioError) {
} else {}
return Future.error(error);
}
}
}
apis.dart
请求的接口管理
import 'package:cookie_jar/cookie_jar.dart';
import 'config.dart';
import 'api_interceptor.dart';
class Api {
static final CookieJar cookieJar = CookieJar();
}
class Apis {
// 注册
static Future<dynamic> register({
required String account,
required String password,
required String code,
required String mobile,
}) async {
Map<dynamic, dynamic> response;
response = (await HttpUtil.post(Urls.register, data: {
"account": account,
"password": password,
"mobile": mobile,
"code": code
}));
return response;
}
// 获取验证码
static Future<dynamic> getCode({required mobile}) async {
Map<String, dynamic> response;
response =
await HttpUtil.get(Urls.getCode, queryParameters: {"mobile": mobile});
return response;
}
// 校对验证码
static Future<dynamic> verifiCode({required mobile, required code}) async {
Map<String, dynamic> response;
response = await HttpUtil.post(Urls.verifiCode,
data: {"mobile": mobile, "code": code});
return response;
}
// 设置新密码
static Future<dynamic> setNewPwd(
{required mobile, required password, required code}) async {
Map<String, dynamic> response;
response = await HttpUtil.post(Urls.setNewPwd,
data: {"mobile": mobile, "password": password, "code": code});
return response;
}
}
国际化
在
flutter
项目中国际化是必不可少的
1. 添加到项目中
1.1. 将此添加到pubspec.yaml文件中。
flutter_localizations:
sdk: flutter
intl: ^0.17.0
flutter_intl:
enabled: true
1.2. 在命令行中运行
flutter packages get
2. 在项目中使用
在main.dart
中添加国际化
@override
Widget build(BuildContext context) {
return GetMaterialApp(
...
// 以下是国际化需要添加的代码
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
S.delegate
], // 中文为首选项,修改后需重启
locale: const Locale('zh', 'CN'),
supportedLocales: [...S.delegate.supportedLocales],
...
);
}
下载完成后,会自动生生以下文件夹
generated
是自动生成的dart
代码I10n
是对应的arb
文件目录
编辑对于同一个词汇,在不同环境对应的内容:
English:
{
"hello": "hello"
}
中文:
{
"hello": "你好"
}
在代码中的使用:
import 'package:flutter/material.dart';
// 引入文件
import 'package:im_flutter_demo/generated/l10n.dart';
class FirstScreen extends StatelessWidget {
FirstScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
// 添加文字
S.of(context).hello,
),
),
);
}
}
WaterMark 水印
水印组件
可以设置行和列的数量、角度以及显示的文字。
import 'package:flutter/material.dart';
class WatermarkWidget extends StatelessWidget {
final int rowCount;
final int columnCount;
final String text;
const WatermarkWidget({
Key? key,
required this.rowCount,
required this.columnCount,
required this.text,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return IgnorePointer(
child: Container(
margin: const EdgeInsets.only(top: 80, bottom: 80),
child: Column(
children: creatColumnWidgets(),
),
),
);
}
// 行
List<Widget> creatRowWdiges() {
List<Widget> list = [];
for (var i = 0; i < rowCount; i++) {
final widget = Expanded(
child: Center(
child: Transform.rotate(
angle: 120,
child: Text(text,
style: const TextStyle(
color: Color.fromARGB(35, 0, 0, 0),
fontSize: 16,
decoration: TextDecoration.none)))));
list.add(widget);
}
return list;
}
// 列
List<Widget> creatColumnWidgets() {
List<Widget> list = [];
for (var i = 0; i < columnCount; i++) {
final widget = Expanded(
child: Row(
children: creatRowWdiges(),
));
list.add(widget);
}
return list;
}
}
如何使用水印
import 'package:flutter/material.dart';
import 'package:im_flutter_demo/src/widgets/water1.dart';
class Index extends StatefulWidget {
const Index({Key? key}) : super(key: key);
@override
State<Index> createState() {
return TextWaterMarkPainterState();
}
}
class TextWaterMarkPainterState extends State<Index> {
OverlayEntry? overlayEntry;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('测试水印')),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
child: const Text("添加水印"),
onPressed: () {
addWaterMarkter(context, "张三 13800138000", 2, 4);
},
),
ElevatedButton(
child: const Text("移除水印"),
onPressed: () {
removeWatermark();
},
),
],
),
),
);
}
// 添加水印
void addWaterMarkter(
BuildContext context, String string, int row, int column) async {
OverlayState? overlayState = Overlay.of(context);
if (overlayEntry == null) {
overlayEntry = OverlayEntry(
builder: (context) => WatermarkWidget(
rowCount: row,
columnCount: column,
text: string,
));
overlayState?.insert(overlayEntry!);
}
}
// 移除水印
void removeWatermark() async {
if (overlayEntry != null) {
overlayEntry!.remove();
overlayEntry = null;
}
}
}
添加后的效果:
移动端适配 flutter_screenutil
flutter_screenutil: ^5.5.3+2
如何使用:
定义页面尺寸常量
static const uIW = 375.0;
static const uIH = 812.0;
在main.dart
中添加,使全局生效
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(Config.uIW, Config.uIH),
minTextAdapt: true,
splitScreenMode: true,
builder: (context, child) {
return MaterialApp(
title: '名称',
builder: EasyLoading.init(),
...
)
});
}
在布局时如何使用:
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class FirstScreen extends StatelessWidget
FirstScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
width: 100.w,
height: 100.h,
)),
);
}
}
图片预览
常用于头像预览,图片预览等场景。
photo_view: ^0.13.0
根据使用场景封装组件:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:photo_view/photo_view.dart';
// 单图片预览
class PhotoViewSimpleScreen extends StatelessWidget {
const PhotoViewSimpleScreen({
Key? key,
required this.imageProvider, //图片
required this.heroTag, //hero动画tagid , 不设置或null为不启用hero动画
this.loadingChild, //加载时的widget
this.backgroundDecoration = const BoxDecoration(color: Colors.black), //背景修饰
this.minScale, //最大缩放倍数
this.maxScale, //最小缩放倍数
}) : super(key: key);
final ImageProvider imageProvider;
final LoadingBuilder? loadingChild;
final BoxDecoration backgroundDecoration;
final dynamic minScale;
final dynamic maxScale;
final String heroTag;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
constraints: BoxConstraints.expand(
height: MediaQuery.of(context).size.height,
),
child: Stack(
children: <Widget>[
Positioned(
top: 0,
left: 0,
bottom: 0,
right: 0,
child: PhotoView(
imageProvider: imageProvider,
loadingBuilder: loadingChild,
backgroundDecoration: backgroundDecoration,
minScale: minScale,
maxScale: maxScale,
heroAttributes: PhotoViewHeroAttributes(tag: heroTag),
enableRotation: true, //是否允许旋转
),
),
GestureDetector(
onTap: () {
// print('context:$context');
Get.back();
},
)
],
),
),
);
}
}
具体使用:
列表展示:
预览效果:
CSS Colors
颜色
CSS Colors package
此包定义
CSS
颜色的颜色常量。这些颜色常量使用dart:ui
中的color
类,这意味着它们对Flutter
应用程序很有用。
1. 在 pubspec.yaml
,添加依赖 css-colors
:
css_colors: ^1.0.0
2. 在命令行中运行
flutter packages get
3. 具体使用
import 'package:css_colors/css_colors.dart';
// 这个就是上面下载的package
import 'package:flutter/material.dart';
void main() {
runApp(const APage());
}
class APage extends StatelessWidget {
const APage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: DemoPage(),
);
}
}
class DemoPage extends StatelessWidget {
const DemoPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(body: Container(color: CSSColors.orange));
}
}
显示页面:
转载自:https://juejin.cn/post/7172889862893207582