zm.blog

select * from learn


  • 首页

  • 标签

  • 分类

  • 归档

  • 关于

  • 搜索

Flutter - 监视页面的切换(RouteObserver & RouteAware)

发表于 2020-08-10 | 分类于 Android , Flutter Tips | | 阅读次数:

经常性的,我们需要监视页面的切换,用以在合适的时候对控件进行动画暂停或者资源释放。

举个栗子:
相机拍照是我们需要经常用到的功能,但是当我们在切换到相机配置页面时,需要暂停当前相机预览,这种情况下我们就需要监视页面的路由变化情况,又或者用户回到应用桌面,此时也需要对相机进行暂停,返回又恢复相机。

在这里主要关系到下面两个方面的:

  1. AppStateLifeRecycle - 今天我们不说这个;
  2. RouteAware

先看看RouteAware是如何定义的?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// An interface for objects that are aware of their current [Route].
///
/// This is used with [RouteObserver] to make a widget aware of changes to the
/// [Navigator]'s session history.
abstract class RouteAware {
/// Called when the top route has been popped off, and the current route
/// shows up.
void didPopNext() { }

/// Called when the current route has been pushed.
void didPush() { }

/// Called when the current route has been popped off.
void didPop() { }

/// Called when a new route has been pushed, and the current route is no
/// longer visible.
void didPushNext() { }
}
阅读全文 »

FlutterBoost混合开发实践与源码解析

发表于 2020-07-06 | 分类于 Android , Flutter Tips | | 阅读次数:

1. 简介

Flutter Boost 是闲鱼团队开发的一个 Flutter 混合开发框架,项目背景可以看看闲鱼的这篇文章:码上用它开始Flutter混合开发——FlutterBoost。

文章中主要讲述了多引擎存在一些实际问题,所以闲鱼目前采用的混合方案是共享同一个引擎的方案。而 Flutter Boost 的 Feature 如下:

  • 可复用通用型混合方案
  • 支持更加复杂的混合模式,比如支持主页Tab这种情况
  • 无侵入性方案:不再依赖修改Flutter的方案
  • 支持通用页面生命周期
  • 统一明确的设计概念

Flutter Boost 采用共享引擎的模式来实现,主要思路是由 Native 容器 Container 通过消息驱动 Flutter 页面容器 Container,从而达到 Native Container 与 Flutter Container 的同步目的。简单的理解,闲鱼想做到把 Flutter 容器做成浏览器的感觉。填写一个页面地址,然后由容器去管理页面的绘制。在 Native 侧我们只需要关心如果初始化容器,然后设置容器对应的页面标志即可。

鉴于网上没有相关的接入文档和使用教程,我这几天也恰好抽空研究了一下,遂整理成文,仅供参考。由于篇幅原因,本文只研究 Android 端的接入与源码,iOS 的部分后续有机会则补充文章来讲解。

注:本文接入的 Flutter Boost 版本为 1.12.13,对应支持的 Flutter SDK 版本为 1.12.13-hotfixes,是目前最新的版本。但 Flutter Boost 版本更新之后,接入方式和使用方式可能会有一些改变,故参考本文时请认准 1.12.13 版本。

阅读全文 »

FlutterUnit开源篇

发表于 2020-04-24 | 分类于 Android , Flutter Tips | | 阅读次数:

FlutterUnit 下载体验:

FlutterUnit.apk 下载 FlutterUnit mac版 下载 Github仓库地址
  • Android下载链接: http://photo.toly1994.com/release/FlutterUnit.apk

  • Mac下载链接: http://photo.toly1994.com/release$flutter_unit_mac.zip

  • ✨ Flutter Unit mac版支持


当前Flutter 版本

1
2
3
4
5
a1@toly ~ % flutter --version
Flutter 1.17.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision e6b34c2b5c (5 days ago) • 2020-05-02 11:39:18 -0700
Engine • revision 540786dd51
Tools • Dart 2.8.1
阅读全文 »

flutter ListView取消头部空白

发表于 2020-04-18 | 分类于 Android , Flutter Tips | | 阅读次数:

ListView头部有一段空白区域,是因为当ListView没有和AppBar一起使用时,头部会有一个padding,为了去掉padding,可以使用MediaQuery.removePadding:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Widget _rubbishList(){
return MediaQuery.removePadding(
removeTop: true,
context: context,
child: Container(
margin: EdgeInsets.only(left: 20,right: 20),
height: ScreenUtil().setHeight(700),
child: ListView.builder(
itemCount: rubbishList.length,
itemBuilder: (context,index){
return _cardItem(index);
}
)
)
);

}
阅读全文 »

Flutter常见数据类型及数据类型转换

发表于 2020-04-08 | 分类于 Android , Flutter Tips | | 阅读次数:

简介

既然 Dart 是一门语言,那么就和我们所知道语言一样,有基本的数据类型以及常见的流程处理语法,那么我们就来了解下。

Dart 的所有东西都是对象,包括数字,函数等。它们都继承自 Object ,默认是都是 null(包括数字),所以数字,字符串都可以调用各种方法。

常亮与变量

变量

使用 var 声明变量,可赋予不同类型的值;未初始化时,默认值为 null ;使用 final 声明一个只能赋值一次的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void main(){

// 声明一个变量 a
var a;
print(a); // 打印 a 的值,显示为 null

a = 10;
print(a); // 打印出来的结果为 10

a = "测试字符串";
print(a); // 打印出来的结果为 测试字符串

a = 30;
print(a); // 打印出来的结果为 30

final b = 10;
b = 20; // 这个会报错,有提示: [dart] 'b', a final variable, can only be set once.

}

  

常量

在 dart 中使用 const 声明常量;使用 const 声明的必须是编译期常量。

1
2
3
4
void main(){
const a = 10;
a = 20; // 这里也会报错:[dart] Constant variables can't be assigned a value.
}
阅读全文 »

flutter抓包

发表于 2020-04-05 | 分类于 Android , Flutter Tips | | 阅读次数:

flutter抓包

查看dio文档发现需要设置代理

1
2
3
4
5
6
7
8
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
client.findProxy = (uri) {
//proxy all request to localhost:8888
return "PROXY 192.168.8.84:8888";
};
// 你也可以自己创建一个新的HttpClient实例返回。
// return new HttpClient(SecurityContext);
};
阅读全文 »

Flutter常见第三方插件

发表于 2020-04-02 | 分类于 Android , Flutter Tips | | 阅读次数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# 网络请求框架
dio: ^3.0.7
# sp
shared_preferences: ^0.5.6
# 微信sdk
fluwx: ^1.2.1+1
# swiper 轮播插件
flutter_swiper: ^1.1.6
# 个推 sdk
getuiflut: ^0.1.6
# Flutter 调试工具
flutter_flipperkit: ^0.0.21
# flipper sqflite调试
flipperkit_sqflite_driver: 0.0.2
# json生成
json_annotation: ^2.2.0
# 下载器
flutter_downloader: 1.1.7
# 获取系统路径
path_provider: ^1.3.0
# 系统权限管理
permission_handler: ^4.3.0
# 通知权限管理
notification_permissions: ^0.4.4
# webview
flutter_webview_plugin: ^0.3.4
# 唤起其他app
url_launcher: ^5.0.2
# growingio 统计
flutter_growingio_track:
path: plugins/flutter_growingio_track-2.6.4
# 设备信息
device_info: ^0.4.0
# 生成uuid
uuid: 2.0.2
# 事件传递
event_bus: ^1.1.0
# loading 样式组件
flutter_spinkit: ^4.0.0
# qq sdk
flutter_qq: ^0.0.5
# 代码包信息
package_info: ^0.4.0+6
# 状态管理
provider: ^3.0.0+1
# 选择器
flutter_picker: ^1.0.13
# 图片裁剪
image_cropper: ^1.0.2
# 图片选择
image_picker: ^0.6.1+2
# 路由框架
fluro: ^1.5.1
# pdf浏览器
flutter_full_pdf_viewer: ^1.0.4
# 避免输入框被键盘遮挡
keyboard_avoider: ^0.1.2
# 屏幕适配 https://github.com/OpenFlutter/flutter_screenutil
flutter_screenutil: ^1.1.0
# Toast插件 https://github.com/OpenFlutter/flutter_oktoast
oktoast: ^2.2.0
# 日期选择器
flutter_cupertino_date_picker: ^1.0.12
# 小红点插件 badge https://pub.dev/packages/flutter_badge
flutter_badge: ^0.0.1
# 自定义上拉加载和下拉刷新效果 flutter_easyrefresh 前提:必须是一个ListView
flutter_easyrefresh: ^1.2.7
# 音频播放插件: https://pub.flutter-io.cn/packages/audioplayers
audioplayers: ^0.13.2
# 录音: https://pub.flutter-io.cn/packages/audio_recorder
audio_recorder:
path: plugins/audio_recorder-1.0.1
# 瀑布流插件 https://github.com/letsar/flutter_staggered_grid_view
flutter_staggered_grid_view: ^0.3.0
# 图片浏览器: https://pub.flutter-io.cn/packages/photo_view
photo_view: ^0.9.0
# 数据加解密
encrypt: 3.3.1
# 网络状态插件connectivity: ^0.4.8+2
connectivity: ^0.4.8+2
# 腾讯im
dim:
path: plugins/dim
# sql
sqflite: ^1.1.7+1
# 富文本输入
extended_text_field: 0.4.9
# 富文本展示
extended_text: ^0.6.6
# 振动
vibration: 1.2.2
# 弹出气泡
w_popup_menu: ^0.2.5
# 高德-仅地图
amap_map_fluttify:
path: plugins/amap_map_fluttify-develop3
# amap_map_fluttify: 0.18.2+c038d50
# 高德-仅定位
amap_location_fluttify: 0.8.11+481e45c
# 图片缓存
cached_network_image: 2.0.0-rc.1
# iOS 内购
flutter_inapp_purchase: ^2.1.0
# 获取设备id: https://pub.flutter-io.cn/packages/unique_ids
unique_ids: 1.0.10
# 获取设备user_agent
flutter_user_agent:
path: plugins/flutter_user_agent-1.2.1
# 颜色插件
color: 2.1.1
# 消息上下轮播(跑马灯)
marquee: 1.3.1
# 为SVG路径和代码生成创建一个纯Dart解析库
path_parsing: 0.1.4
# 异常捕获及日志打印
# https://pub.flutter-io.cn/packages/sentry
sentry: 3.0.1
# 基于dio的网络请求日志
dio_log: ^1.3.3
# 支付代码测试
iap_pay:
git:
url: https://gitee.com/Steven_Hu/iap_pay.git
ref: master
阅读全文 »

flutter国际化本地化

发表于 2020-03-30 | 分类于 Android , Flutter Tips | | 阅读次数:

源码地址

安装,配置和使用

安装

将此添加到包的pubspec.yaml文件中:

1
2
dependencies:
flutter_translate: <latest version>

从命令行(或从您的编辑器)安装软件包:

1
flutter pub get

组态

导入flutter_translate:

1
导入 'package:flutter_translate / flutter_translate.dart' ;

将json本地化文件放置在项目中您选择的文件夹中。

默认情况下,flutter_translate将assets/i18n在项目根目录下的目录中搜索本地化文件。

在中声明您的资产本地化目录 pubspec.yaml

1
2
3
flutter:
assets:
- assets/i18n

在主函数中,创建本地化委托并启动应用,然后将其与LocalizedApp包装在一起

1
2
3
4
5
6
7
8
void main() async
{
var delegate = await LocalizationDelegate.create(
fallbackLocale: 'en_US',
supportedLocales: ['en_US', 'es', 'fa']);

runApp(LocalizedApp(delegate, MyApp()));
}

如果本地化文件的资产目录与默认目录(assets/i18n)不同,则需要指定它:

1
2
3
4
var delegate = await LocalizationDelegate.create(
...
basePath: 'assets/i18n/'
...

示例MyApp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 class MyApp extends StatelessWidget {

@override
Widget build(BuildContext context) {

var localizationDelegate = LocalizedApp.of(context).delegate;

return LocalizationProvider(
state: LocalizationProvider.of(context).state,
child: MaterialApp(
title: 'Flutter Translate Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
localizationDelegate
],
supportedLocales: localizationDelegate.supportedLocales,
locale: localizationDelegate.currentLocale,
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(),
),
);
}
}
阅读全文 »

Flutter父子组件通信

发表于 2020-03-18 | 分类于 Android , Flutter Tips | | 阅读次数:

父->子

定义父组件变量 data,在子组件Child的构造方法中把data值传进去,子组件接收data。

父->子

子组件接收callBack并调用callBack将data值传过去。
父组件定义onChanged,绑定到callBack中,接收子组件传过来的data值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ParentState extends State<Parent> {
String data = "父组件传递给子组件的值";

void onChanged(val){
setState(() {
data = val;
});
}

@override
Widget build(BuildContext context) {
......
//省略非关键代码
new Child(data: data,callBack: (value)=>onChanged(value)),
}
}
class child extends StatefulWidget {
childTwo({Key key, this.data, this.callBack}) : super(key: key);
final callBack;
String data;

@override
void initState() {
data = widget.data;
super.initState();
}
......
//省略非关键代码
widget.callBack(data);
}
阅读全文 »

Flutter自定义轮播图Banner

发表于 2020-03-14 | 分类于 Android , Flutter Tips | | 阅读次数:

widget_banner.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import 'dart:async';


import 'package:ajbaby/enum/enum_indicator_style.dart';
import 'package:ajbaby/route_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';


/*
* 自定义banner
*/
// ignore: must_be_immutable
class CustomBanner extends StatefulWidget {
List<String> images;
double height;
ValueChanged<int> onTap;


IndicatorStyle indicatorStyleStr;


CustomBanner({
Key key,
@required this.images,
@required this.indicatorStyleStr,
this.height = 375,
this.onTap,
}) : super(key: key);


@override
_CustomBannerState createState() => _CustomBannerState();
}


class _CustomBannerState extends State<CustomBanner> {
PageController _pageController;
int _curIndex;
Timer _timer;


@override
void initState() {
super.initState();
_curIndex = widget.images.length * 5;
_pageController = PageController(initialPage: _curIndex);
_initTimer();
}


@override
void dispose() {
// TODO: implement dispose
super.dispose();
// _cancelTimer();
}


@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
_buildPageView(),
_buildIndicator(),
],
);
}


Widget _buildIndicator() {
var length = widget.images.length;
return Positioned(
bottom: 5,
child: Row(
children: widget.images.map((s) {
return Padding(padding: const EdgeInsets.symmetric(horizontal: 3.0), child: _indicatorStyle(s, length));
}).toList(),
),
);
}


Widget _indicatorStyle(s, length) {
switch (widget.indicatorStyleStr) {
case IndicatorStyle.circle:
return Container(
child: ClipOval(
child: Container(
width: ScreenUtil().setWidth(8),
height: ScreenUtil().setHeight(8),
color: s == widget.images[_curIndex % length] ? Color(0xFFFF5F6D) : Color(0xFFE0E0E0),
),
));
break;
case IndicatorStyle.line:
return Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Container(
width: ScreenUtil().setWidth(20),
height: ScreenUtil().setHeight(3),
color: s == widget.images[_curIndex % length] ? Color(0xFFFF5F6D) : Color(0xFFE0E0E0),
),
));
break;
}
return null;
}


Widget _buildPageView() {
var length = widget.images.length;
return Container(
height: ScreenUtil().setHeight(widget.height),
child: PageView.builder(
controller: _pageController,
onPageChanged: (index) {
setState(() {
_curIndex = index;
if (index == 0) {
_curIndex = length;
_changePage();
}
});
},
itemBuilder: (context, index) {
return GestureDetector(
onPanDown: (details) {
_cancelTimer();
},
onTap: () {
//弹出路由,跳转到其他页面
Navigator.of(context).pushNamed(RouteNames.productDetails);
// Scaffold.of(context).showSnackBar(
// SnackBar(
// content: Text('当前 page 为 ${index % length}'),
// duration: Duration(milliseconds: 500),
// ),
// );
},
child: Image.network(
widget.images[index % length],
fit: BoxFit.cover,
),
);
},
),
);
}


/// 点击到图片的时候取消定时任务
_cancelTimer() {
if (_timer != null) {
_timer.cancel();
_timer = null;
_initTimer();
}
}


/// 初始化定时任务
_initTimer() {
if (_timer == null) {
_timer = Timer.periodic(Duration(seconds: 3), (t) {
_curIndex++;
_pageController.animateToPage(
_curIndex,
duration: Duration(milliseconds: 300),
curve: Curves.linear,
);
});
}
}


/// 切换页面,并刷新小圆点
_changePage() {
Timer(Duration(milliseconds: 350), () {
_pageController.jumpToPage(_curIndex);
});
}
}

引用

1
2
3
4
5
child: CustomBanner(
images: _imgData,
indicatorStyleStr: IndicatorStyle.line,
height: double.infinity,
),
阅读全文 »
1…567…38
ZhangMiao

ZhangMiao

Android/Flutter Developer

379 日志
58 分类
143 标签
RSS
E-Mail QQ Github StackOverflow
友情链接
  • Kaisir
  • Liujianhui
  • Leo
  • Hongyang
  • Liuwangshu
  • Jspang
  • Blankj
  • WuXiaoLong
  • Molunerfinn
  • Ofind
  • Gcssloop
© 2024 ZhangMiao
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
本站访客数 人次 本站总访问量 次