关于flutter:Flutter应用Windows安装包创建教程

[TOC] 本文中,咱们将会应用 Inno Setup 这个软件来为 Flutter 利用创立 Windows 安装包。 装置 Inno Setup首先装置 Inno Setup 这个软件,在 Inno Setup Downloads 下载安装 Inno Setup,下载地址在这里 https://jrsoftware.org/isdl.php 创立 Windows 安装包编译 Flutter APP应用命令行编译 Flutter APP 的 Windows 版本 flutter build windows --release 这里输入的 build/windows/runner/Release 目录就是编译好的软件目录。 创立安装包脚本关上 Inno Setup,抉择 Create a new script file using the Script Wizard 而后点击 “下一步”,在上面这个页面,填写利用的根本信息 下一步,批改利用文件夹名称 而后就进入到了比拟要害的页面了,上面的页面中,抉择利用蕴含的文件 留神上图中 ①②③ 的阐明: ① 抉择利用的可执行文件,在我的项目目录的 build/windows/runner/Release/利用名称.exe ② 增加利用蕴含的 dll 文件,这里抉择的是 Release 目录下最外层的 dll 文件 ...

March 4, 2024 · 1 min · jiezi

关于flutter:手把手带你自研一套Flutter动态热更新框架深入Dart语言具备解析并自由篡改AST

手把手带你自研一套Flutter动静热更新框架//xia仔ke:百度网盘把握Flutter底层机制,从基本解决的相干概念知识点与技巧详解 一、Flutter底层机制概述Flutter是Google开源的挪动UI框架,以其高性能、跨平台的个性受到宽泛关注。为了从根本上解决Flutter开发中的各种问题,了解其底层机制至关重要。Flutter的底层机制次要包含渲染引擎、Dart语言、Widget模型、事件处理等方面。 二、Flutter底层机制的相干概念知识点渲染引擎:Flutter应用自定义的Skia渲染引擎,反对硬件加速,可能在不同的平台上实现高性能的渲染。了解Skia渲染引擎的原理和个性,对于优化Flutter利用的性能至关重要。Dart语言:Flutter应用Dart作为开发语言,Dart具备垃圾回收、动态类型查看等个性。把握Dart语言的根底语法、异步编程、性能优化等方面的常识,是编写高效Flutter利用的根底。Widget模型:Flutter采纳申明式UI模型,通过Widget形容界面。了解Widget的生命周期、状态治理、自定义Widget等方面的常识,对于构建简单、可保护的Flutter利用至关重要。事件处理:Flutter通过事件处理机制响应用户交互。理解Flutter的事件传递机制、事件处理函数、手势辨认等方面的常识,有助于实现晦涩、天然的用户交互体验。 三、Flutter底层机制的技巧详解优化渲染性能:通过正当应用Flutter的渲染机制,如应用懒加载、缩小不必要的重绘和布局计算等,能够进步利用的渲染性能。此外,理解Skia渲染引擎的优化技巧,如应用缓存、缩小绘制调用等,也能够进一步晋升渲染性能。Dart语言性能优化:Dart语言的性能优化次要包含缩小内存占用、进步代码执行效率等方面。能够通过防止不必要的对象创立、正当应用数据结构、缩小嵌套循环等形式来优化Dart代码的性能。Widget高效应用:在Flutter开发中,正当应用Widget能够大大提高利用的性能。例如,应用StatelessWidget和StatefulWidget依据需要抉择适当的Widget类型;通过继承现有Widget实现自定义Widget;防止在build办法中执行耗时的操作等。事件处理优化:优化事件处理能够进步利用的响应速度和用户体验。能够通过缩小事件处理的提早、正当应用手势识别器、防止事件冒泡等形式来优化事件处理性能。 四、总结把握Flutter底层机制是解决开发中遇到的各种问题的要害。通过深刻理解渲染引擎、Dart语言、Widget模型、事件处理等方面的知识点和技巧,咱们能够从根本上进步Flutter利用的性能、可维护性和用户体验。同时,一直学习和摸索新的技术趋势和实践经验,将有助于咱们在Flutter开发中不断进步和翻新。

March 2, 2024 · 1 min · jiezi

关于flutter:FlutterWinChat基于flutter3xbitsdojowindowgetx电脑端仿微信实例

春节期间,吃饱喝足,寻思着年前有应用flutter3开发过一款App聊天利用,索性应用flutter3开发一款桌面端仿微信exe聊天我的项目Flutter_Winchat。 在通过了半个多月的开发,flutter3桌面聊天我的项目正式开发结束! 在开发的过程中,的确遇到了一些问题,不过好在最初都解决了。 想着这个我的项目还算不错,就和小伙伴们做一些分享。 应用技术编辑器:vscode窗口治理:bitsdojo_window: ^0.1.6托盘图标:system_tray: ^2.0.3路由/状态治理:get: ^4.6.6本地存储:get_storage: ^2.1.1图片预览插件:photo_view: ^0.14.0网址预览:url_launcher: ^6.2.4视频组件:media_kit: ^1.1.10+1文件选择器:file_picker: ^6.1.1整个我的项目应用到了下面的一些技术,窗口治理采纳的bitsdojo_window插件,不过window_manager这个窗口治理插件也不错,不过绝对重量级一些。 https://pub-web.flutter-io.cn/packages/bitsdojo_window https://pub-web.flutter-io.cn/packages/window_manager 我的项目构造 通过flutter create app_proj创立一个新我的项目。应用flutter run -d windows来运行到window桌面。 通过 system_tray 插件治理flutter桌面端任务栏托盘图标。https://pub-web.flutter-io.cn/packages/system_tray main.dart入口治理import 'dart:io';import 'package:flutter/material.dart';import 'package:bitsdojo_window/bitsdojo_window.dart';import 'package:get/get.dart';import 'package:get_storage/get_storage.dart';import 'package:media_kit/media_kit.dart';import 'package:system_tray/system_tray.dart';import 'utils/index.dart';// 引入公共款式import 'styles/index.dart';// 引入公共布局模板import 'layouts/index.dart';// 引入路由配置import 'router/index.dart';void main() async { // 初始化get_storage存储类 await GetStorage.init(); // 初始化media_kit视频套件 WidgetsFlutterBinding.ensureInitialized(); MediaKit.ensureInitialized(); initSystemTray(); runApp(const MyApp()); // 初始化bitsdojo_window窗口 doWhenWindowReady(() { appWindow.size = const Size(850, 620); appWindow.minSize = const Size(700, 500); appWindow.alignment = Alignment.center; appWindow.title = 'Flutter3-WinChat'; appWindow.show(); });}class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return GetMaterialApp( title: 'FLUTTER3 WINCHAT', debugShowCheckedModeBanner: false, theme: ThemeData( primaryColor: FStyle.primaryColor, useMaterial3: true, // 修改windows端字体粗细不统一 fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null, ), home: const Layout(), // 初始路由 initialRoute: Utils.isLogin() ? '/index' :'/login', // 路由页面 getPages: routes, onInit: () {}, onReady: () {}, ); }}// 创立系统托盘图标Future<void> initSystemTray() async { String trayIco = 'assets/images/tray.ico'; SystemTray systemTray = SystemTray(); // 初始化系统托盘 await systemTray.initSystemTray( title: 'system-tray', iconPath: trayIco, ); // 右键菜单 final Menu menu = Menu(); await menu.buildFrom([ MenuItemLabel(label: 'show', onClicked: (menuItem) => appWindow.show()), MenuItemLabel(label: 'hide', onClicked: (menuItem) => appWindow.hide()), MenuItemLabel(label: 'close', onClicked: (menuItem) => appWindow.close()), ]); await systemTray.setContextMenu(menu); // 右键事件 systemTray.registerSystemTrayEventHandler((eventName) { debugPrint('eventName: $eventName'); if (eventName == kSystemTrayEventClick) { Platform.isWindows ? appWindow.show() : systemTray.popUpContextMenu(); } else if (eventName == kSystemTrayEventRightClick) { Platform.isWindows ? systemTray.popUpContextMenu() : appWindow.show(); } });}flutter3路由/状态治理采纳 getx 作为路由和状态治理。将 MaterialApp 替换为GetMaterialApp 组件。 ...

March 2, 2024 · 8 min · jiezi

关于flutter:我用-Flutter-Gemini-写了一个水贴-APP

我用 Flutter Gemini 写了一个水贴 APP 视频https://youtu.be/sEpJWfNwbmk https://www.bilibili.com/video/BV1gH4y177sy/ 前言原文 https://ducafecat.com/blog/flutter-gemini-ai-integration本文通过 Flutter 插件 google_generative_ai 疾速的集成了 google ai gemini 来实现一个水贴的工具。 代码https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_gemini gemini 介绍门户站https://gemini.google.com/ 开发站https://ai.google.dev/ Google Cloud 免费https://console.cloud.google.com 参考https://medium.com/flutter/harness-the-gemini-api-in-your-dar... https://ai.google.dev/tutorials/dart_quickstart?hl=zh-cn https://ai.google.dev/models/gemini?hl=zh-cn 技术限度限度国家 IP 限度模拟器运行,须要真机运行 筹备工作获取 gemini api keyhttps://aistudio.google.com/app/apikey?hl=zh-cn 模型阐明https://ai.google.dev/models/gemini?hl=zh-cn 测试无效申请地址 url https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=YOUR_API_KEY参数 { "contents": [ { "parts": [ { "text": "介绍下如何疾速学习 Flutter." } ] } ]}postman 测试 Flutter 开发步骤增加 pub 包pubspec.yaml dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 google_generative_ai: ^0.2.1 dio: ^5.4.1 flutter_markdown: ^0.6.20插件包站: ...

February 28, 2024 · 5 min · jiezi

关于flutter:尝鲜flutter3桌面版微信EXE

春节期间,吃饱喝足,闲着没事就捣鼓Flutter3在桌面端开发的各种可行性。于是就开发了一个flutter3桌面端微信EXE程序。 目前该我的项目大部分性能前端性能曾经开发结束,还有一些小性能正在欠缺中... 发一些预览图,让大家尝尝鲜~~ 顺便能够给点倡议或意见!

February 27, 2024 · 1 min · jiezi

关于flutter:一个仿小红书app端项目一个礼拜的小成果

一个仿小红书app端我的项目(一个礼拜的小成绩)B站链接

February 23, 2024 · 1 min · jiezi

关于flutter:开发经验Flutter中对CustomScrollViewSliver组件截长图

问题分享以后页面的需要,有时须要对页面进行截图。Flutter中截图个别应用RepaintBoundary搭配GlobalKey获取Widget的截图(PlatformView 无奈截图)。 然而当须要截图的指标是CustomScrollView时,尤其是应用了SliverPersistentHeader等Sliver组件时,不容易想出RepaintBoundary的嵌套地位,也就无奈获取长截图。 计划百度根本查不到有用的信息,甚至还有一些离奇的计划: 下面长截图的现实状况是 SingleChildScrollView 这种容许咱们在 child 套一层 RepaintBoundary,但理论中也可能是 CustomScrollView 这种严格限度 children 类型的,此时咱们可能就须要借助相似 SliverToBoxAdapter 这种容器,并且在每个 child 上都套一个 RepaintBoundary在每个 child 上都套一个 RepaintBoundary 显然是十分十分蹩脚的计划,在拍脑袋之前,咱们尽可能的多检索一些材料: https://github.com/SachinGanesh/screenshot/issues/10#issuecomment-586302204 原文: In your ListView that you wanna take a full screenshot, put a NeverScrollableScrollPhysics on it, then what is going to take control of the scrolling is the SingleChildScrollView.意思就是给你的CustomScrollView一个NeverScrollableScrollPhysics,而后扔到SingleChildScrollView中进行截图。 很显然这个计划是更适合的,因为不须要关怀每一个child,因为child的数量可能尤其的多,难以去追踪CustomScrollView的每一个child。 解决组件: GlobalKey paintKey = GlobalKey();// 是否处在打印模式bool printMode = false;@overrideWidget build(BuildContext context) {// 页面Widget body = CustomScrollView( physics: printMode ? NeverScrollableScrollPhysics() : null,);// 截图中if (printMode) { body = AbsorbPointer( child: SingleChildScrollView( child: RepaintBoundary( key: paintKey, child: Container( color: ColorPlate.lightGray, child: body, ), ), ), ),}return body;}截图办法: ...

February 23, 2024 · 1 min · jiezi

关于flutter:盘点主流-Flutter-状态管理库2024

盘点支流 Flutter 状态治理库2024 视频https://youtu.be/nLQ2nmW8FKk https://www.bilibili.com/video/BV1U6421M7dw/ 前言原文 https://ducafecat.com/blog/flutter-state-management-libraries...状态治理是每个利用不可短少的,本文将会盘点下支流的状态治理包。 对了 我还对插件包做了整顿,欢送移步查看 https://flutter.ducafecat.com . 状态治理作用数据共享和同步:在应用程序中,不同局部可能须要共享和同步数据。通过状态治理,能够轻松地在应用程序的各个局部之间共享数据,并确保数据的一致性。UI更新:Flutter状态治理能够帮忙开发者管理应用程序中的UI状态,以便在数据变动时更新用户界面。这样能够确保应用程序的UI与数据的状态放弃同步。简单状态治理:随着应用程序变得越来越简单,管理应用程序的状态变得更加艰难。Flutter状态管理工具能够帮忙开发者更无效地管理应用程序的状态,使代码更具可维护性和可扩展性。性能优化:无效的状态治理能够帮忙应用程序防止不必要的重绘和从新构建,从而进步应用程序的性能和响应速度。代码构造:通过良好的状态治理,开发者能够更好地组织应用程序的代码构造,使其更易于了解和保护。考量纬度编写代码的复杂度,是否简洁实用规模(小型、中大型、参加人数、迭代频率)开发团队的前端组件化教训我的项目是否疾速开发,MVPProvider 轻量级、易学习、内置于Flutter中,实用于根本状态治理。 https://pub.dev/packages/provider import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';/// This is a reimplementation of the default Flutter application using provider + [ChangeNotifier].void main() { runApp( /// Providers are above [MyApp] instead of inside it, so that tests /// can use [MyApp] while mocking the providers MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => Counter()), ], child: const MyApp(), ), );}/// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool// ignore: prefer_mixinclass Counter with ChangeNotifier, DiagnosticableTreeMixin { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } /// Makes `Counter` readable inside the devtools by listing all of its properties @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(IntProperty('count', count)); }}class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const MaterialApp( home: MyHomePage(), ); }}class MyHomePage extends StatelessWidget { const MyHomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Example'), ), body: const Center( child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('You have pushed the button this many times:'), /// Extracted as a separate widget for performance optimization. /// As a separate widget, it will rebuild independently from [MyHomePage]. /// /// This is totally optional (and rarely needed). /// Similarly, we could also use [Consumer] or [Selector]. Count(), ], ), ), floatingActionButton: FloatingActionButton( key: const Key('increment_floatingActionButton'), /// Calls `context.read` instead of `context.watch` so that it does not rebuild /// when [Counter] changes. onPressed: () => context.read<Counter>().increment(), tooltip: 'Increment', child: const Icon(Icons.add), ), ); }}class Count extends StatelessWidget { const Count({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Text( /// Calls `context.watch` to make [Count] rebuild when [Counter] changes. '${context.watch<Counter>().count}', key: const Key('counterState'), style: Theme.of(context).textTheme.headlineMedium, ); }}BLoC/Cubit: ...

February 22, 2024 · 6 min · jiezi

关于flutter:Flutter-NestedScrollView-内嵌视图滚动行为一致

Flutter NestedScrollView 内嵌视图滚动行为统一 视频https://www.bilibili.com/video/BV1Gh4y1571p/ 前言上一节讲了 CustomScrollView ,能够发现有的中央滚动并不是很连贯。 这时候就须要 NestedScrollView 来解决了。 明天会写一个如下图的例子来实现滚动统一。 原文 https://ducafecat.com/blog/flutter-sliver-nested-scroll-view参考https://api.flutter.dev/flutter/widgets/NestedScrollView-clas... https://api.flutter.dev/flutter/widgets/SliverOverlapAbsorber... https://api.flutter.dev/flutter/widgets/SliverOverlapInjector... 知识点 NestedScrollViewNestedScrollView 是 Flutter 中的一个 Widget,它能够嵌套多个滚动视图,例如 ListView、GridView、SliverAppBar 等。NestedScrollView 能够让多个滚动视图联动滚动,从而实现一些简单的交互成果。 常见的业务场景: 一个页面上有多个可滚动的区域,而且这些区域之间的滚动是互相独立的,然而它们的滚动行为须要协调一致,比方一个列表和一个悬浮的顶部栏。实现相似于网易云音乐个人主页的成果,即在滚动过程中,一个悬浮的头部会被逐步放大,同时顶部的导航栏会突变隐没,直到最初整个头部齐全占据整个屏幕。在列表中嵌套一个可滚动的子列表,例如在一个电商利用中,展现一个大分类下的多个小分类,每个小分类上面又有多个商品。 NestedScrollView 和 CustomScrollView 都是反对自定义滚动视图的 Widget。它们的区别在于,CustomScrollView 能够通过增加多个 Sliver 来实现简单的滚动视图成果,而 NestedScrollView 则是将多个滚动视图嵌套在一起,并提供了一些不便的接口来协调它们之间的滚动。因而,NestedScrollView 的应用场景更加适宜于多个可滚动区域之间须要协调滚动的状况。 步骤NestedScrollView 分为头部和内容两个局部,咱们别离来实现。 第一步:实现 NestedScrollView 头部lib/nested.dart 编写头部组件函数,创立页面 NestedScrollPage class NestedScrollPage extends StatefulWidget { const NestedScrollPage({super.key}); @override State<NestedScrollPage> createState() => _NestedScrollPageState();}class _NestedScrollPageState extends State<NestedScrollPage> { final List<String> _tabs = const ['tab1', 'tab2', "tab3", "tab4"];筹备 _tabs 数据build 函数 ...

February 22, 2024 · 4 min · jiezi

关于flutter:flutter-sliver-多种滚动组合开发指南

flutter sliver 多种滚动组合开发指南 视频https://youtu.be/4mho1kZ_YQU https://www.bilibili.com/video/BV1WW4y1d7ZC/ 前言有不少同学工作中遇到须要把几个不同滚动行为组件(顶部 appBar、内容固定块、tabBar 切换、tabBarView视图、自适应高度、横向滚动)黏贴成一个组件。 这时候就须要 sliver 出场了,本文将会写一个多种滚动的组合。 业务场景剖析上面是淘宝、小红书的常见状况。 原文 https://ducafecat.com/blog/flutter-sliver-scroll知识点 sliverSliver 是 Flutter 中用于构建可滚动视图的根本构建块之一。Sliver 是可滚动区域中的一小部分,具备固定的大小和地位,能够依据须要动静加载和卸载。Sliver 通常用于创立高性能、高度灵便的可滚动视图,例如列表、网格、瀑布流等。 在 Flutter 中,有许多不同类型的 Sliver 组件,每个组件都有特定的作用和用处。上面是一些常见的 Sliver 组件: SliverAppBar:一个带有滚动成果的利用栏,能够在向上滚动时暗藏,并在向下滚动时显示。SliverList:将子组件搁置在一个垂直列表中,能够依据须要动静加载和卸载列表项。SliverGrid:将子组件搁置在一个网格中,能够依据须要动静加载和卸载网格项。SliverPadding:为子组件提供填充,以使它们与其余 Sliver 组件的大小和地位保持一致。SliverToBoxAdapter:将一个一般的组件包装成一个 Sliver 组件,以便将其搁置在 CustomScrollView 中。参考步骤第一步:Sliver 横向滚动lib/page.dart Widget _mainView() { return CustomScrollView( slivers: [ // 横向滚动 SliverToBoxAdapter( child: SizedBox( height: 100, child: PageView( children: [ Container( color: Colors.yellow, child: const Center(child: Text('横向滚动')), ), Container(color: Colors.green), Container(color: Colors.blue), ], ), ), ), ...SliverToBoxAdapter 进行包装能力 slivers 应用。 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Sliver Scroll')), body: _mainView(), ); }第二步:固定高度的 tabView return CustomScrollView( slivers: [ ... // 固定高度内容 SliverToBoxAdapter( child: Container( height: 200, color: Colors.greenAccent, child: const Center(child: Text('固定高度内容')), ), ), // tabView 内容 SliverToBoxAdapter( child: DefaultTabController( length: 3, child: Column( children: [ const TabBar( tabs: [ Tab(text: 'Tab 1'), Tab(text: 'Tab 2'), Tab(text: 'Tab 3'), ], ), SizedBox( height: 200, child: TabBarView( children: [ Container(color: Colors.yellow), Container(color: Colors.green), Container(color: Colors.blue), ], ), ), ], ), ), ),外层嵌套 DefaultTabController ,能力让 TabBar、TabBarView 顺利工作。第三步:自适应高度的 tabView实现 SliverPersistentHeaderDelegate 抽象类 ...

February 22, 2024 · 3 min · jiezi

关于flutter:Flutter插件开发指南02-事件订阅-EventChannel

Flutter插件开发指南02: 事件订阅 EventChannel 视频 https://www.bilibili.com/video/BV1zj411d7k4/前言 上一节咱们讲了 Channel 通道,然而如果你是卫星定位业务,原生端被动推音讯给 Flutter 这时候就要用到 EventChannel 通道了。本节会写一个 1~50 的计数器,到 50 后主动敞开原生的音讯订阅。 FlutterEventChannel FlutterEventChannel 的作用是在 Flutter 平台和原生平台之间建设双向通信的桥梁。通过 FlutterEventChannel,Flutter 应用程序能够向原生平台发送事件,同时也能够接管来自原生平台的事件。FlutterEventChannel 能够用于许多场景,例如: 传感器数据采集:许多应用程序须要从设施的传感器(如加速度计、陀螺仪、磁力计等)中获取数据。Flutter 应用程序能够通过 FlutterEventChannel 发送申请,让原生平台采集传感器数据并返回到 Flutter 应用程序中。后台任务实现告诉:当应用程序在后盾运行时,可能须要执行一些长时间运行的工作。Flutter 应用程序能够通过 FlutterEventChannel 向原生平台发送申请,让原生平台在后台任务实现时发送告诉到 Flutter 应用程序中。音频和视频流传输:许多应用程序须要在 Flutter 应用程序和原生平台之间传输音频和视频流。Flutter 应用程序能够通过 FlutterEventChannel 向原生平台发送申请,让原生平台传输音频和视频流并返回到 Flutter 应用程序中。这使得 Flutter 应用程序能够应用原生平台的音频和视频解决性能,以进步应用程序的性能和用户体验。FlutterEventChannel 执行过程如下: Flutter 应用程序创立一个 FlutterEventChannel 对象,并指定一个惟一的通道名称。Flutter 应用程序调用 FlutterEventChannel 的 receiveBroadcastStream 办法,以获取一个 Stream 对象,以便监听来自原生平台的事件。原生平台创立一个 EventChannel 对象,并指定与 Flutter 应用程序中通道名称相匹配的字符串。原生平台调用 EventChannel 的 setStreamHandler 办法,以设置一个 StreamHandler 对象,以便接管来自 Flutter 应用程序的事件并向其发送原生事件。当 Flutter 应用程序须要向原生平台发送事件时,它会将事件数据发送到 FlutterEventChannel 对象中。FlutterEventChannel 将事件数据传递给原生平台的 EventChannel 对象。EventChannel 对象将事件数据传递给 StreamHandler 对象中的 onListen 办法。在 onListen 办法中,原生平台能够执行一些操作并发送事件数据到 Stream 对象中。Flutter 应用程序能够通过 Stream 对象监听来自原生平台的事件,并执行相应的操作。须要留神的是,FlutterEventChannel 中应用的 Stream 对象是异步的,因而在监听来自原生平台的事件时须要应用异步编程的技术。另外,在应用 FlutterEventChannel 时,Flutter 应用程序和原生平台之间须要约定好通道名称和事件数据格式,以便可能正确地交互和解决数据。 ...

February 20, 2024 · 1 min · jiezi

关于flutter:Flutter插件开发指南01-通道Channel的编写与实现

Flutter插件开发指南01: 通道Channel的编写与实现 视频 https://www.bilibili.com/video/BV1ih4y1E7E3/前言 本文将会通过一个加法计算,来实现 Channel 的双向通信,让大家有个一个领会。 Flutter插件Flutter插件是Flutter应用程序与原生平台之间的桥梁,使得Flutter应用程序能够与原生代码进行交互,从而扩大Flutter应用程序的性能和能力。Flutter插件通常包含Dart和原生代码(例如Java、Kotlin或Objective-C、Swift等),并能够通过Flutter插件框架来注册、治理和调用。在整个Flutter架构中,Flutter插件具备十分重要的作用和重要性。以下是Flutter插件在Flutter架构中的一些重要作用: 扩大Flutter应用程序的性能:Flutter插件能够提供许多原生平台的性能和能力,例如拜访原生设施API、拜访原生UI组件等。通过应用Flutter插件,Flutter应用程序能够取得更多的性能和能力,从而能够更好地满足用户需要。进步Flutter应用程序的性能:通过应用Flutter插件,Flutter应用程序能够通过原生平台API来执行某些工作,从而能够进步应用程序的性能和响应速度。例如,应用原生平台的图像处理库来解决大量图像数据。与原生代码进行交互:Flutter插件能够使Flutter应用程序与原生代码之间进行双向通信,从而能够让Flutter应用程序与原生平台进行无缝集成。这对于须要与现有原生应用程序集成的Flutter应用程序来说尤为重要。促成Flutter生态系统的倒退:Flutter插件能够提供许多不同类型的性能和能力,例如拜访原生设施传感器、拜访原生广告库等。通过将这些插件共享给其余Flutter开发者,Flutter插件能够促成Flutter生态系统的倒退和壮大,使得更多的开发者可能应用Flutter来构建高质量的应用程序。Channel 通道 Channel是Flutter应用程序与原生平台之间进行通信的桥梁。Flutter应用程序和原生平台能够通过Channel来替换音讯和数据,从而实现双向通信。Flutter插件通常蕴含一个或多个Channel,用于与原生代码交互。Channel在Flutter插件开发中的作用有以下几个方面: 提供双向通信:Channel提供了Flutter应用程序与原生平台之间进行双向通信的能力。Flutter应用程序能够向原生平台发送音讯和数据,原生平台也能够向Flutter应用程序发送音讯和数据。治理办法调用:Channel能够用于治理Flutter应用程序和原生平台之间的办法调用。Flutter应用程序能够通过Channel调用原生平台的办法,原生平台也能够通过Channel调用Flutter应用程序的办法。实现数据传输:Channel能够用于在Flutter应用程序和原生平台之间传输数据。Flutter应用程序能够通过Channel向原生平台发送数据,原生平台也能够通过Channel向Flutter应用程序发送数据。扩大Flutter应用程序的性能:通过应用Channel,Flutter应用程序能够拜访原生平台的性能和能力,例如拜访原生设施API、拜访原生UI组件等。这能够扩大Flutter应用程序的性能和能力,从而能够更好地满足用户需要。 原文 https://ducafecat.com/blog/flutter-plugin-channel 参考 https://docs.flutter.dev/packages-and-plugins/developing-pack...步骤 第一步:创立插件应用 Android Studio 创立插件 我的项目类型 plugin选的语言是 java object-c平台选了所有 all 创立实现后 目录、文件名阐明 ios原生 android原生 linux原生 macos原生 windows原生 lib/flutter_plugin_add_platform_interface.dart性能接口定义 lib/flutter_plugin_add_method_channel.dart原生性能接口实现 lib/flutter_plugin_add_web.dartWeb性能接口实现 lib/flutter_plugin_add.dartflutter 接口调用类 第二步:编写 android 代码首先咱们用模拟器把 android 我的项目运行下,让 android gradle 主动拉取依赖。抉择 example 来运行。 关上我的项目的正确目录是 example/android,而不是根目录的 android,否则依赖包认不出。 关上后能失常认出 如果认不出能够清下缓存 选取革除历史和缓存文件 编写加法计算android/src/main/java/com/ducafecat/flutter_plugin_add/FlutterPluginAddPlugin.java  @Override  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {    if (call.method.equals("getPlatformVersion")) {      result.success("Android " + android.os.Build.VERSION.RELEASE);    }    // add    else if (call.method.equals("add")) {      int a = call.argument("a");      int b = call.argument("b");      int sum = add(a, b);      result.success(sum);    }    else {      result.notImplemented();    }  } Flutter应用程序通过MethodChannel向原生平台发送办法调用申请时。原生平台收到Flutter应用程序的办法调用申请后,依据申请的办法名执行相应的办法后,将执行后果返回给Flutter应用程序。   private int add(int a, int b) {    return a + b;  }第三步:编写 flutter 接口代码接口配置pubspec.yaml  plugin:    platforms:      android:        package: com.ducafecat.flutter_plugin_add        pluginClass: FlutterPluginAddPlugin      ios:        pluginClass: FlutterPluginAddPlugin      linux:        pluginClass: FlutterPluginAddPlugin      macos:        pluginClass: FlutterPluginAddPlugin      windows:        pluginClass: FlutterPluginAddPluginCApi      web:        pluginClass: FlutterPluginAddWeb        fileName: flutter_plugin_add_web.dart platforms 局部定义了 Flutter 插件在以下不同平台上的反对: ...

February 20, 2024 · 1 min · jiezi

关于flutter:Flutter-Web-实现ChatGPT对话与Function-Call

Flutter-ChatGPT基于Flutter Web实现ChatGPT多轮聊天、翻译、Prompt文本生成、企业知识库、本地文档问答、functions\_call等性能,页面流式输入采纳StreamBuilder Widget实现,各业务模块Repository均提供直连OpenAI接口与python后端API接口流式输入性能实例 Github仓库地址backend采纳FastApi实现后端LangChain调用OpenAI接口 backend-data提供初始化向量文档,构建向量索引代码位于vector\_index.pybackend-servicefunction_call.py提供openai function call相干实例性能model_query.py提供python办法调用参数封装模型,波及文档问答与多轮对话vector_index.py提供本地知识库/上传文档向量化相干实例性能backend-env提供设置OpenAI参数设置[OPENAI\_API\_KEY] # openaiopenai.log = "debug"openai.api_key = os.environ["OPENAI_API_KEY"]backend-main.py提供FastApi接口性能实例,包含response stream流解决 backend-requirments.txt依赖组件配置,可通过terminal执行 pip install -r requirments.txtfrontend采纳Flutter实现Web-UI(Material3)性能,具体性能可查看screenshot,已减少页面字符国际化配置 frontend-dbweb浏览器IndexedDB数据库操作与模型实例 frontend-pages业务功能模块,蕴含以下内容: 智能对话智能翻译智能写作智能文档智能工作各模块遵循repository-model-provider-view分包形式各view模块按性能复杂度拆分widgets与states具体拆分粒度按理论业务要求解决,尽可能执行部分刷新通过[go\_router][StatefulShellBranch]实现各页面路由状态治理通过Riverpod治理Widget UI-States(https://riverpod.dev/)页面逐字打印采纳SteamBuild Widget实现,具体代码如下message\_bot.dart: /// /// 流式申请[request task stream message] /// Stream<String>? stream(WidgetRef ref, bool mounted) { return //ref.read(taskStateProvider.notifier).sendMessageStream('', '', () { ref.read(taskStateProvider.notifier).sendMessageStreamApi('', '', () { if (!mounted) return; ref.read(allowInputTaskProvider.notifier).update((state) => false); }, () { if (!mounted) return; ref.read(allowInputTaskProvider.notifier).update((state) => true); }); } /// /// StreamBuilder /// class MessageBotStream extends ConsumerWidget { const MessageBotStream(this.stream, this.controller, {super.key}); final Stream<String>? stream; //滚动管制 final ScrollController controller; @override Widget build(BuildContext context, WidgetRef ref) { return StreamBuilder( stream: stream, key: Key('${Random().nextDouble()}'), builder: (BuildContext context, AsyncSnapshot<String> snapshot) { if (snapshot.hasError) { return Text("${t.app.error}: ${snapshot.error}"); } if (snapshot.hasData) { String content = snapshot.data ?? ""; scrollEnd(controller, 200); if (content.isNotEmpty) return Text(content); } return const MessageLoading(); }, ); } }frontend-assets提供业务模块应用图标与i18n国际化语言配置,slang国际化内容生成gen ...

September 25, 2023 · 1 min · jiezi

关于flutter:Flutter-Fair原理篇之Fair逻辑动态化通信实现

Fair 逻辑动态化,是对一期布局动态化的加强。为了实现逻辑动态化,咱们过后思考了多种计划,计划次要集中在这三个方面,一种是对google提供的JIT进行裁切,第二种是自定义解析引擎,第三种借助js的能力。 上面次要讲一下几方面: 架构的标准化通信协议的实现js文件的加载与开释数据的绑定音讯的散发第三方扩大(用户依据须要扩大更精彩的性能)一、架构的标准化当咱们生成了布局文件和逻辑文件,接下来要做的是如何建设他们之间的分割,确切的说是如何建设两者之间的通信。为了不便资源的管制与调配,fair是对每一个逻辑js通过惟一的key确认,而后通过key-value的模式将逻辑文件长期贮存在一个全局的汇合中。因这个key在生成js的时候是不确定的,所以咱们对key对立定义名称为#FairKey# ,在js发送到native侧之前,由dart侧全局替换该值为具体的key。这个key十分重要,在音讯通信的时候,须要通过key获取具体的通信对象,js侧dart侧都是,原理如下图。 上面是生成js文件的格局: //该对象用于全局治理各个js对象let GLOBAL = {};...//'#FairKey#'会在发送之前全局对立替换GLOBAL['#FairKey#']={ ... //转换之后的js内容,蕴含对应的变量和办法 ...}二、通信协议的实现js与布局文件的通信,实质上就是js与dart之间的通信,因为两者都是以native平台做依靠,所以须要native作为音讯的转发器,负责音讯的散发。对于dart与native之间的通信,咱们应用的是官网提供的message-channel与dart:FFI。message-channel次要有、BasicMessageChannel、MethodChannel、EventChannel,该通道次要用于异步通信,dart:FFI是官网提供的间接调用native c/c++代码的工具,次要用于同步通信。对于native与js之间的通信,咱们则能够用注入办法的模式建立联系,native侧注入本地办法,那么js则能够调用该办法发送音讯并获取后果值,而如果是js提供本地办法, 那native侧能够执行js中的办法获取js发送的后果。 2.1 格局定义为了不便数据的对立解决,须要规定数据格式,数据的解决逻辑次要集中在js侧和dart侧,native侧只负责数据的转发,以及js的加载和开释。 { pageName:"对应的调用页名称,也就是js侧的#FairKey#", funcType:"调用类型,method,variable等", args:{ //用户携带的参数,交由js侧解决 }}2.2 通道创立对于通道的创立,目前次要是用了三种,对于js的加载以及开释用的是MethodChannel,对于js-native之间的通信采纳的是BasicMessageChannel和dart:FFI。之所以采纳两种通道的起因,也是为了拆散加载开释和音讯发送的流程。 2.3 各侧接口定义dart侧与js侧的分割,次要是波及到同步和异步通信,所以在设计接口办法的时候也是做了辨别。 为了抹平平台的差异性,对于js侧的通信通过的是办法的注入,native侧只负责音讯的转发,不做太多的逻辑,所以js侧只注入了一个办法,逻辑的解决交给js侧解决,办法会依据音讯的字段type来执行具体的操作。 三、JS文件的加载与开释咱们通过对dsl布局的解析生成widget树,用于UI的展现,对于外面的逻辑,咱们放到js中去解决。所以咱们须要波及到js的加载,用于数据绑定,当页面销毁之后咱们对应的也须要开释掉js,升高对内存的耗费,同时须要防止出现反复加载问题。 3.1 js文件的加载流程js文件的加载次要分为以下几步:读取本地或者网络的js数据对js数据包装成固定格局的json字符串通过method-channel调用native端的加载办法native端js引擎加载胜利之后返回音讯告诉dart端,js加载实现。 3.2 js文件的开释流程当页面销毁之后,须要销毁js文件,耗费的步骤如下: 当widget的onDispose回调被执行的时候,调用dart侧的开释办法dart通过method-channel调用native端的开释办法native调用js侧办法,js会依据pageName获取制订的js对象,并将相干对象从汇合中移除,后续回收就交给js引擎解决了js移除胜利之后,native侧移除相干js-Object,实现开释开释胜利之后告诉dart侧,开释过程实现。 四、数据的绑定当js加载实现之后,接下来的工作就是须要做数据的绑定了。对于数据的绑定,绑定的是变量和办法,本文只写办法的调用,对于调用形式会在接下来的文章进行分享。在js加载实现之后,dart端会调用getBindVariableAndFunc办法获取js侧的数据,数据包包含js侧办法名称、变量名称、变量名对应的值。每一个FairWidget都会有一个固定的key,在js侧也会有一个对应的key,dart给js侧发送音讯的时候,会通过key获取js侧的对象,而后进行相干操作。dart中的布局被解析成给各个节点,对于外面的js逻辑则会解析成js,js代码中会对应具体的变量以及办法,所以咱们要做的是建设dart与js之间的通信,用于获取变量值,执行相干办法等。所有的数据都是在js侧解决,只有js调用setState的办法的时候才会将数据发送到dart侧,刷新页面数据。 获取js侧的数据格式如下: { "func":["办法A名","办法B名"], "variable":{ "变量a名":"变量a值", "变量b名":"变量b值", "变量c名":"变量c值", ... }}咱们获取到这些数据之后就会将数据绑定到RuntimeFairDelegate中去,当理论调用的时候从外面依据名称取出来对应数据绑定就能够了。 五、音讯散发音讯的散发次要是指dart-js两者音讯可能正确的发送和接管,而保障音讯可能正确的接管发送,是通过FairKey来确定的。音讯的发送分两局部,一部分是js发送音讯给dart,当用js侧调用setState和调用invokeFlutterCommonChannel的时候会发送音讯给dart侧,其中invokeFlutterCommonChannel是native侧注入的办法,setState是js侧注入的办法,是对invokeFlutterCommonChannel的包装;另一部分是dart发送音讯给js侧,例如获取js侧绑定数据、调用js侧办法的时候,通过Runtime中的办法即可通信。对于dart侧办法的调用,会有同步调用和异步调用。异步调用的实现形式是通过message-channel,同步则通过dart:FFI的模式。  5.1 通信过程 js通信dart(js发送音讯到dart次要是异步通信)通过调用js侧invokeFultterChanne办法,将音讯发送到native侧,native再对音讯转发至dart侧。 5.2 Dart侧音讯散发当dart侧接管到js发送的音讯的时候,dart侧会对音讯分类,而后发送到正确的指标。对与dart侧音讯的接管次要是在message handler的中散发音讯,具体散发过程是依据音讯的funcName字段作辨别,来自js侧的音讯目前只有两种,一种是js侧拓展发送过去的音讯,第二种是setState发送过去的音讯。当funcName名称为invokePlugin的时候是用户拓展模块发来的音讯,对setState发送过去的音讯,会依据pageName散发到指定的FairWidget中去。 六、三方拓展js转dart的时候,有些性能是js不反对的,例如dart端用的通信是Dio,权限调用,拍照,相册抉择,那么js转换的时候是有问题的,会因为没有找到对应的类而报错,js只做逻辑解决所以对于这些性能须要用户自定义封装,上面是封装根本流程: 6.1 封装Dart侧封装dart侧,须要继承IFairPlugin接口,并实现外面的getRegisterMethods办法,如下所示。 //实现IFairPlugin的getRegisterMethods办法,暴露出对应js侧的办法class FairPhotoSelector extends IFairPlugin { Future<dynamic> getPhoto(dynamic map) async { //具体的逻辑实现, return Future.value(); } @override Map<String, Function> getRegisterMethods() { var functions = <String, Function>{}; //用户须要注册办法,这个办法与js侧对应 functions.putIfAbsent('getPhoto', () => getPhoto); return functions; }}6.2 封装JS侧js侧的封装比较简单,只须要调用invokeFlutterCommonChannel办法传递给Native,而后再传递给Dart侧,如下所示。 ...

September 23, 2023 · 1 min · jiezi

关于flutter:Fltter-Fair逻辑动态化架构设计与实现

本文的核心内容包含: 数据逻辑解决布局中的逻辑解决Flutter类型数据处理一、数据逻辑解决咱们接触的每一个Flutter界面,大多由布局和逻辑相干的代码组成。如Flutter初始工程的Counting Demo的代码: class _MyHomePageState extends State<MyHomePage> { // 变量 int _counter = 0; // 办法 void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), // 内部参数 ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter', // 变量应用 style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, // 事件回调 tooltip: 'Increment', child: Icon(Icons.add), ), ); }}如上,正文标记的就是页面中的数据以及数据处理逻辑局部。Fair的逻辑动态化是要实现这部分变量、办法等内容的脚本级动静解析以及DSL布局属性的绑定和后续用户操作事件办法的调用。 ...

September 21, 2023 · 3 min · jiezi

关于flutter:Fair下发产物布局DSL生成原理

一、概述大家都晓得,Flutter在release环境是以AOT模式运行的,这就决定了咱们要做动态化的话无奈简略的通过动静下发dart代码执行的。依据Fair团队的后期调研,咱们对布局动态化和逻辑动态化的实现采纳了两套不同的实现计划,对于布局局部,咱们在解析dart源文件之后生成DSL产物下发,而后在端上解析DSL构建布局的形式,逻辑动态化的局部,咱们采纳的是dart源码转js下发的形式。 整个动态化流程大抵如下: 二、整体流程概述详述具体流程之前,咱们先来看看整体的流程,而后再去解说各个流程的原理细节。 整个流程大抵分为两局部: 通过fair_ast_gen将源码解析并生成AstMap;通过fair_dsl_gen将AstMap转换成咱们须要的Fair DSL。这里波及到两个概念,大家须要先理解一下 AST 全称是Abstract Syntax Tree,中文名为形象语法树。DSL 全称是Domain Specific Language,中文名为畛域特定语言。三、AST解析3.1 源码解析要把dart源码转换成咱们须要的DSL,首先要对dart源码进行形象语法分析,这里是整个转换过程的第一个关键点,甚至能够说是整个DSL生成的根底。好在dart 官网提供了解析工具包analyzer,这为咱们整个的dsl生成工作大大加重了工作量。 analyzer包的utilities类提供了parseFile函数,这个函数返回的CompilationUnit,实际上是一个编译单元,继承自AstNode,正是咱们前面AST解析的入口。 3.2 AST解析后面咱们提到,AST是一种与编程语言无关的形象语法树,对于这块的概念不是太熟同学,咱们还是先看一个小例子。比方上面这段代码: 那如果转换成AST的话,差不多是上面这样的: 理论转换产物很长,咱们只截取一部分,不过能够大抵看出AST的整个构造,能够看出,整个AST实际上是对源码的一个树状构造形容,整个构造里蕴含很多节点对象,每个节点上面又蕴含各种树形和子节点。 咱们将100+的语法节点分类形象为标识符、字面量、表达式、语法块,其它五大类,30+种的罕用节点,同时剥离了与Fair产物解析无关的信息,只保留原始node中的要害信息,使得节点解析更加清晰。 后面咱们说到analyzer的praseFile办法解析完dart源文件后返回了AstNode实例,咱们对AstNode的剖析次要由该类的accept办法提供,这里用到了访问者设计模式。 accept办法接管的参数类型是AstVisitor,这是一个接口,咱们正是通过这个接口的一系列办法实现对上述实例中各个节点的遍历的。 正如下面的例子看到的,原始AstNode数据量很大,哪怕是一个简略的Demo,解析进去的AST实际上是蕴含很多节点信息的,所以咱们并不通过实现AstVisitor接口来实现所有节点类型的拜访。analayzer包提供了SimpleAstVisitor,咱们能够继承这个类来自定义Visitor,按须要抉择咱们反对的节点去实现办法就能够了。相干代码如下: 最初返回的是一个Map类型的Ast节点树,感兴趣的同学能够间接通过源码理解细节 四、DSL生成4.1 从AST到DSL生成流程以下是AST到DSL的整个生成的过程: 有了第一步生成的AST语法树Map产物,再依据AST Map来生成DSL就比拟好了解了。在DSL的生成流程当中,次要是对节点的遍历,而后针对办法,表达式和变量的解决。 因为DSL次要解决的是布局动态化的局部,实际上对于一个Wiget的解析解决,咱们次要是针对build办法中return的内容局部进行了提取并生成DSL(此处的methodMap,咱们先放到前面再解说,并不影响对主流程的了解)。相应代码如下所示: 对于DSL的格局,在debug环境,为了不便调试与直观的发现问题,咱们的产物采纳json格局,在线上环境,处于产物大小的管制及解析速度的思考,咱们下发产物格局改为flatbuffer(google推出的一种高性能,小体积的序列化计划)。 4.2 布局动态化原理实际上有了analyzer作为根底,DSL的生成在技术上的难点并不大,可是咱们的DSL的构造应该是什么样的,这取决于fair在运行时怎么对DSL进行还原,毕竟咱们的DSL生成最初是为了动静还原成Wiget树并渲染的。针对这部分内容,咱们做个大抵的理解,这样能更好的了解上面的内容。 咱们晓得,Flutter因为某些起因,对dart:mirror包进行了移除,这就决定了咱们没法通过反射对DSL进行布局构建还原,不过Flutter还有一个万能的办法Function.apply。 这个办法,是咱们动态化计划中的第二个重要办法,是Widget树还原的根底。 端上接管到下发的DSL后,只能解析到对应的字符串String类型,咱们只需将对应的String映射到对应的办法(此处次要反对构造方法和类静态方法),便能够将对应的DSL还原并构建Widget树。在fair当中,大抵是这样的。此处咱们写了一个工具库,以不便对flutter widget映射关系的主动生成。 4.3 DSL构造理解了fair对DSL解析执行的大抵原理之后,咱们再来了解DSL的大抵构造就比拟容易了。 下面的className对应的是下面映射关系中的key,na和pa对应的是可选命名参数和位参数,此处咱们须要解释的是下面提到的methodMap。所谓的methodMap,从字面意思上了解,其实就是办法缓存,在这里咱们同样以下面的HelloWord类为例。 能够看到,在咱们的示例中build办法嵌套了一个布局构建办法_buildText()。后面咱们讲到,在布局动态化DSL生成过程中,咱们次要是对build办法进行了提取,对于这种办法嵌套的布局构建代码,咱们该怎么解决呢。 大抵的应答办法有几种: 在框架层面做限度,不反对这种写法;解析时提取嵌套办法返回的Widget内容,在开发时反对办法嵌套,理论生成DSL时变成纯Widget嵌套形式;缓存嵌套的Widget构建办法,在运行时解析Json内容后对函数进行实时的替换。以上形式中,显然1是让人不可承受的,如果要接入动态化框架有这样的限度,恐怕会让应用的开发者望而生畏。至于办法2和办法3,其实大同小异,一个是在解析时替换,一个是在运行时替换,思考到咱们生成DSL尽量不要扭转原有的代码构造,咱们抉择了计划3。这就是为什么咱们的DSL Json中须要有methodMap的起因。 以下面HelloWord类DSL解析后果为例,能够看到methodMap当中实际上缓存的是除build办法外的Widget构建的相干办法。 4.4 变量和表达式的解决下面咱们次要讲的都是办法的解决,然而对于变量和表达式,比方上面这种: Text('$_counter')以及这种: onPressed: _incrementCounter这两种类型的变量援用,在AST中实际上对应的不同的类型,然而如果在DSL中咱们还是简略的解决成了字符串,理论在DSL解析时就无奈与一般字符串进行辨别了,这里咱们采取了一种比较简单的形式,在通过增加不同的特殊符号前缀进行了辨别。 例如下面两个示例,解决后如下: Text('$_counter') => #($_counter)onPressed: _incrementCounter => @(incrementCounter)而后,在Fair解析反对层面通过正则匹配到不同的表达式类型,来做变量的数据绑定曾经办法的逻辑调用等。 ...

September 21, 2023 · 1 min · jiezi

关于flutter:如何为-Flutter-应用程序创建环境变量

咱们为什么须要环境变量? 次要用于存储高级秘密数据,如果泄露可能会危及您产品的安全性。这些变量本地存储在每个用户的本地零碎中,不应该签入存储库。每个用户都有这些变量的正本。 配置在根我的项目中创立一个名为 .env 的文件夹(文件夹名称由您抉择)在 .gitignore 中增加 .env 文件夹门路为 .env/在 .env 文件夹中增加环境文件,如 dev.json 、staging.json 、prod.json 、testing.json 或任何你想创立的环境。 步骤通过 CLI 设置环境变量 运行命令: flutter run --dart-define-from-file=.env/dev.json设置 VSCode 运行环境变量 在 .vscode/ 文件夹中创立 launch.json 文件,从而创立启动配置。为每个环境创立配置,并在 toolArgs 字段中增加选项 --dart-define-from-file=.env/dev.json,如下所示:{ "version": "0.2.0", "configurations": [ { "name": "mobile_app dev", "request": "launch", "type": "dart", "toolArgs": [ "--dart-define-from-file=.env/dev.json" ] }, { "name": "mobile_app staging", "request": "launch", "type": "dart", "toolArgs": [ "--dart-define-from-file=.env/staging.json" ] }, { "name": "mobile_app prod", "request": "launch", "type": "dart", "toolArgs": [ "--dart-define-from-file=.env/prod.json" ] }, { "name": "mobile_app testing", "request": "launch", "type": "dart", "toolArgs": [ "--dart-define-from-file=.env/testing.json" ] } ]}设置从Android Studio运行的环境变量 ...

August 27, 2023 · 1 min · jiezi

关于flutter:深入理解-Flutter-图片加载原理-京东云技术团队

前言随着Flutter稳固版本逐渐迭代更新,京东APP外部的Flutter业务也日益增多,Flutter开发为咱们提供了高效的开发环境、优良的跨平台适配、丰盛的性能组件及动画、靠近原生的交互体验,但随之也带来了一些OOM问题,通过线上监控信息和Observatory工具联合剖析咱们发现问题的起因是因为Flutter页面中加载的大量图片导致的内存溢出,这也是在原生开发中常见的问题之一,Flutter官网为咱们提供的Image widget实现图片加载及显示,只有理解Flutter中图片的加载原理及图片内存治理形式能力真正发现问题的实质,本文将重点介绍Flutter中图片的加载原理,应用过程中有哪些须要留神的中央及优化思路和伎俩,心愿能给大家带来一些启发和帮忙。 根本应用上面是 Image 的根本应用办法,image参数是 Image 控件中的必选参数,也是数据源类型能够是Asset、网络、文件、内存,上面将以咱们罕用的网络图片加载形式为例子解说原理,根本应用如下: Image( image: NetworkImage( "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"), width: 100.0, heitht: 100.0) Image 控件的应用办法这里就不在开展了,控件的参数及API详情请参阅:https://api.flutter.dev/flutter/widgets/Image-class.html 图片加载流程Flutter 的图片加载原理与原生客户端中的图片框架加载原理类似,具体可点击下方大图查看,加载步骤如下: 1、 辨别数据起源生成缓存列表中数据映射的惟一key; 2、 通过key读取缓存列表中的图片数据; 3、 缓存存在,返回已存在的图片数据; 4、 缓存不存在,按起源加载图片数据,解码后同步到缓存中并返回; 5、 设置回调监听图片数据加载状态,数据加载实现后从新渲染控件显示图片; 大家可能留神到了下面流程图中的文件缓存局部是灰色的,目前官网还不反对此性能,上面咱们会通过源码逐渐剖析加载流程及如何通过批改源码补全文件缓存性能。 源码剖析上面将通过流程图联合UML类图剖析图片加载流程: 这个UML类图看起来略微有点儿简单,但认真看会发现已将图片数据加载流程分成几大模块,上面将依照模块进行逐渐剖析,上面将以网络图片加载形式为例解说外围类和外围办法性能。 外围类及办法介绍启动缓存相干类PaintingBinding:图片缓存类和着色器预加载,该类是基于框架的应用程序启动时绑定到Flutter引擎的胶水类,在启动入口main.dart的runApp办法中创立WidgetsFlutterBinding类时被初始化的,通过笼罩父类的initInstances()办法初始化外部的着色器预加载(Skia第一次在GPU上绘制须要编译相应的着色器,这个过程大略20ms~200ms)及图片缓存等,图片缓存以单例的形式(PaintingBinding.instance.imageCache)对外提供办法应用,也就是说这个图片缓存在APP中是全局的,并在这个类中还提供了图像解码(instantiateImageCodec)、缓存革除(evict)等性能。 ImageCache:图片缓存类,默认提供缓存最大个数限度1000个对象和最大容量限度100MB,因为图片加载过程是一个异步操作,所以缓存的图片分为三种状态:已应用、已加载、未应用,别离对应三个图片缓存列表,当图片列表超限时会将图片缓存列表中最近起码应用图片进行删除,缓存列表别离是:沉闷中图片缓存列表(\_cache)、已加载图片缓存列表(\_pendingImages)、未沉闷图片缓存列表(_liveImages),并对外提供以下办法:获取缓存(putIfAbsent)、清空缓存(clear、clearLiveImages)、驱赶单个图片(evict)、最大缓存个数限度(maximumSize)、最大缓存大小限度(maximumSizeBytes)等办法。   从源码中咱们能够看到缓存列表是Map类型,Flutter中的Map创立的对象是LinkedHashMap是有序的,按键值插入程序迭代,Flutter应用LinkedHashMap存储图片数据并实现相似LRU算法的缓存,当缓存列表中的图片被应用后会将图片数据从新插入到缓存列表的开端,这样最近起码应用的图片始终会被放在列表的头部。 当缓存列表减少图片数据后,会通过最大缓存个数和最大缓存大小两个纬度进行查看缓存列表是否超限,若存在超限状况则通过Map的keys.first办法获取缓存列表头部最近起码应用的图片对象进行删除,直到满足缓存限度。 启动缓存小结: Flutter启动后在PaintingBinding中创立ImageCache缓存,图片缓存是全局的并以单例形式对外提供应用办法,缓存默认最大个数限度1000个对象、最大容量限度100MB,缓存中的Map列表通过key/value形式存储图片信息,并通过keys.first办法实现的相似LRU算法治理图片缓存列表,对外提供putIfAbsent()办法获取已缓存图像,若缓存中不存在则通过回调图片加载类中的load()办法加载图片数据,另外图片缓存中还提供clear()和evict()办法用来删除缓存。 图片数据加载相干类ImageProvider:图片数据提供抽象类,该类定义了图像数据解析办法(resolve)、惟一key生成办法(obtainKey)、数据加载办法(load),obtainKey 和load办法均由子类实现,obtainKey办法生成的对象用于内存缓存的key值应用,load办法将依照不同数据源加载图像数据,罕用的Provider子类有:NetworkImage、AssetImage、FileImage、MemoryImage,咱们能够看到resolve办法返回的是图片加载对象类(ImageStream),load办法返回的是ImageStreamCompleter类用来治理图像加载状态及图像数据(ImageInfo)。 ImageStreamCompleter:是一个抽象类,用于治理加载图像对象(ImageInfo)加载过程的一些接口,Image控件中正是通过它来监听图片加载状态的。 ImageStream:图像的加载对象,可监听图像数据加载状态,由ImageStreamCompleter返回一个ImageInfo对象用于图像显示 NetworkImage:网络图片加载类,ImageProvider的实现类,通过URL加载网络图像,笼罩load()办法返回ImageStreamCompleter的实现类MultiFrameImageStreamCompleter,构建该类须要一个codec参数类型是Future<ui.Codec>,通过调用_loadAsync()办法下载网络图片数据取得字节流后通过调用PaintingBinding.instance.instantiateImageCodec办法对数据进行解码后取得Future<ui.Codec>对象,obtainKey办法咱们发现返回的是SynchronousFuture<NetworkImage>(this)对象,正是NetworkImage 本人自身,咱们通过该类的==办法能够看到判断两个NetworkImage类是否相等通过runtimeType 、url 、scale 这三个参数来判断,所以图片缓存中的key相等判断取决于图片的url、scale、runtimeType参数。 MultiFrameImageStreamCompleter:是ImageStreamCompleter的子类是Flutter SDK的预置类,构建该类须要一个codec参数类型是Future<ui.Codec>,Codec 是解决图像编解码器的句柄也是Flutter Engine API的包装类,可通过其外部的frameCount变量获取图像帧数,别离解决单帧和多帧(动态图)图像,外部的getNextFrame()办法获取每帧的图像数据并创立Image控件中渲染须要的ImageInfo数据,调用onImage办法将ImageInfo返回给Image控件。 图像数据加载小结: 下面以网络图像加载流程剖析,首先通过ImageProvider的resolve()办法创立ImageStream对象,obtainKey()办法创立图像缓存列表中的惟一key(取决于图像url和scale),通过load()办法加载图像数据并返回MultiFrameImageStreamCompleter对象,并将其设置给ImageStream中的setCompleter()办法增加监听图像加载实现状态,图像数据通过Codec 解决帧数别离解决最终创立ImageInfo对象通过ImageStreamListener的onImage办法返回给Image控件。 图片渲染相干类_ImageState:是Image控件创立的State类,通过调用ImageProvider的resolve()办法解析图片数据,resolve()办法返回的ImageStream对象,通过addListener()减少图片解析状态监听,通过ImageStreamListener的onImage回调中获取图片数据(ImageInfo)加载实现状态,onChunk回调监听数据加载进度,onError监听图片加载谬误状态,最终通过调用setState进行数据更新绘制。 仔细的同学会发现ImageProvider的实例对象(widget.image)被ScrollAwareImageProvider包装了一下又从新创立了一个provider,在ScrollAwareImageProvider外部次要是重写了其中的resolveStreamForKey()办法,Flutter SDK 1.17版本中对图片解析减少了疾速滚动优化,当判断以后屏幕处在疾速滚动状态时,则将图片解析过程提早下一帧帧尾进行。 ...

August 16, 2023 · 1 min · jiezi

关于flutter:推荐10个Flutter开源项目

作为跨平台利用开发的领头羊,Flutter从已公布就受到宽广开发者的追捧。应用Flutter技术开发的利用不仅体验上有限靠近原生利用,在开发效率上也是其余技术无法比拟的。随着其开发者社区的一直壮大,Flutter生态系统曾经相当弱小,并且泛滥开源应用程序也相继诞生。这些开源利用不仅展现了Flutter的多功能性,而且还为开发者提供了贵重的资源和灵感。本着无私奉献的精力,本文收集了还在保护的十大最受欢迎的Flutter开源利用。 1,Flutter GalleryFlutter Gallery 是一个由Flutter团队本人开发的开源利用,目标是为了帮忙开发者学习Flutter的各种UI组件和设计模式。该应用程序提供了如何实现不同部件和性能的实在例子,使其成为初学者和经验丰富的Flutter开发人员的绝佳资源。Flutter Gallery简洁而直观的界面使其易于浏览和摸索Flutter宽泛的 widget 目录。并且,此我的项目反对Android、iOS、web、macOS、Linux和Windows简直所有的零碎,真正实现了跨平台。 我的项目链接:https://github.com/flutter/gallery 2,Flutter WooCommerce appFlutter E-commerce 是一个弱小的开源应用程序,为应用Flutter构建电子商务应用程序提供了残缺的解决方案。它提供了一系列的基本功能,如产品列表、购物车性能、用户认证和领取集成。Flutter WooCommerce带有一个丑陋的、响应式的用户界面,能够很容易地定制,以合乎特定的品牌要求。凭借其模块化的架构和欠缺的代码库,该应用程序可作为心愿建设本人的电子商务应用程序的开发人员的贵重参考。 我的项目链接:https://github.com/woosignal/flutter-woocommerce-app 3,Flutter NewsFlutter News 是一个用Flutter构建的风行的开源新闻应用程序。它聚合了来自不同起源的新闻文章,并在一个洁净和视觉上吸引人的界面中展现它们。该利用提供的性能包含个性化的新闻举荐,将文章退出书签,以及在社交媒体平台上分享新闻。Flutter News展现了如何在Flutter利用中整合API,解决异步操作,并实现晦涩的滚动和导航。不过,此我的项目曾经有3年没有更新了,可能间接运行的话会有很多的报错。 我的项目链接:https://github.com/theindianappguy/FlutterNewsApp 4,Flutter ChatFlutter Chat 是一个开源的音讯利用模板,容许开发者轻松创立聊天利用。它为构建实时聊天性能提供了根底,包含发送文本信息、媒体共享和推送告诉等性能。Flutter Chat精心设计的用户界面和灵便的架构使其成为心愿在其应用程序中增加聊天性能的开发者的热门抉择。该利用还展现了解决数据同步和治理用户存在的最佳实际。 我的项目链接:https://github.com/duytq94/flutter-chat-demo 5,FeatherFeather 是一个应用Flutter开发的漂亮而直观的开源天气利用。它提供实时的天气信息,包含以后条件、每小时的预测和扩大预测。Flutter Weather与天气API集成,获取并显示精确的天气数据。凭借其吸引人的视觉效果和晦涩的动画,这个应用程序展现了如何应用Flutter创立引人入胜和信息丰盛的天气应用程序。 我的项目链接:https://github.com/jhomlala/feather 6,Flutter TravelFlutter Travel 是一个开源的游览应用程序,展现了Flutter在构建视觉上令人惊叹和功能丰富的应用程序方面的能力。该应用程序容许用户摸索风行的游览目的地,查看无关景点的详细信息,并打算他们的旅行。Flutter Travel利用Flutter弱小的动画框架来创立令人欢快的过渡和互动。它还展现了解决简单UI布局和整合地图和位置服务的最佳实际。 我的项目链接:https://github.com/JideGuru/FlutterTravel  7,FlutterGramFlutterGram 是一个社交分享开源我的项目,旨在复制风行的社交媒体应用程序Instagram的外围性能和用户界面。它为应用Flutter构建照片分享和社交网络应用提供了一个根底。该应用程序包含上传照片、利用过滤器、对帖子进行喜爱和评论以及关注其余用户等性能。Flutter Instagram Clone的简洁和响应式设计使它成为有趣味建设本人的社交媒体应用程序的开发者的一个很好的终点。 我的项目链接:https://github.com/JideGuru/FlutterTravel 8,Flutter Music PlayerBlackHole 是一个音乐播放器的开源应用程序,它提供了一个全功能的音乐播放器界面,应用 Flutter 技术开发。目前,反对浏览和播放音乐、创立播放列表和治理音乐库等性能。该应用程序提供了一个视觉上吸引人的用户界面,具备晦涩的动画和过渡成果。Flutter音乐播放器演示了如何在Flutter应用程序中应用媒体播放API,解决音频流,以及实现直观的音乐管制。 我的项目链接:https://github.com/Sangwan5688/BlackHole 9,Flutter FitnessWger project 是一个开源的健身利用,帮忙用户跟踪他们的锤炼,设定指标,并监测他们的停顿。它提供了锤炼记录、锤炼历史和个性化训练打算等性能。Flutter Fitness展现了如何通过交互式图表、进度跟踪和游戏化元素来发明吸引人的用户体验。该应用程序的简洁设计和直观的导航使其成为有趣味应用Flutter构建健身和衰弱相干应用程序的开发者的贵重资源。 我的项目链接:https://github.com/wger-project/flutter 10,Flutter QuizFlutter Quiz 是一个开源的测验应用程序模板,使开发人员可能创立交互式测验应用程序。它为创立具备各种问题类型和难度的多选题测验提供了一个灵便的框架。Flutter Quiz包含分数跟踪、定时测验和后果剖析等性能。该应用程序的直观用户界面和晦涩的动画使其成为应用Flutter构建教育和游戏化测验应用程序的一个平凡终点。 ...

July 12, 2023 · 1 min · jiezi

关于flutter:参与-2023-第二季度官方-Flutter-开发者调查

Flutter 3.10 曾经正式公布,每个季度一次的 Flutter 开发者考察也来啦!邀请社区的各位成员们填写: 调研旨在理解你对 Flutter 的称心水平以及对其各个子系统的反馈。你的意见将对咱们改良 Flutter 的性能和性能产生重要影响。 在这次调研中,咱们会持续通过对 Flutter 外围框架、Dart 语言、Flutter Package 生态、Material Design 和 Cupertino 系列 widget、开发者资源等方面的问题进行继续跟踪调查来评估 Flutter 的各方面的状况。 同时,咱们还将询问你对于 Firebase 和设施端机器学习性能在 Flutter 利用开发中的应用状况。咱们心愿理解你对这些性能的满意度,并收集你的倡议以晋升开发者体验。 新增的考察内容还有:你目前应用的 Flutter 公布渠道、更新频率、危险偏好等方面,咱们心愿通过这方面的反馈来理解你对不同渠道和更新策略的认识。你的答复将帮忙咱们更好地满足其余开发者的需要。 你的答复将依据 Google 隐私权政策进行解决,也同时能够是全匿名参加。咱们将对收集到的数据进行汇总和剖析,以便更好地理解开发者对 Flutter 的应用体验。 无论你是初学者还是有多年 Flutter 开发教训的专家,你的参加对咱们都十分重要。咱们心愿听到你的声音,独特改良 Flutter 的开发体验,为开发者社区发明更好的环境。 参加本次调研的工夫不会太长,你能够随时来到调研页面,并在不便的时候返回持续填写。调研截止日期为 2023 年 7 月 2 日 截止,心愿能够有机会在此之前失去你的反馈和倡议! 点击下方链接,即可开始填写问卷,期待你的宝贵意见! https://flutter.cn/urls/23q2

June 26, 2023 · 1 min · jiezi

关于flutter:flutter截图方案

截图分两种: 1.原生能力截图1、原生能力截图分为Android和iOS,Android不能间接截取蕴含flutter和原生界面的截图,只能独自截取flutter或者原生界面 //android截Native界面外围代码Window window = this.activity.getWindow();View view = this.activity.getWindow().getDecorView().getRootView();view.setDrawingCacheEnabled(true);Bitmap bitmap = Bitmap.createBitmap( view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); // Bitmap()Canvas canvas = new Canvas(bitmap);view.draw(canvas);//Android截flutter界面外围代码View view = this.activity.getWindow().getDecorView().getRootView();view.setDrawingCacheEnabled(true);Bitmap bitmap = null;if (this.renderer.getClass() == FlutterView.class) { bitmap = ((FlutterView) this.renderer).getBitmap();} else if(this.renderer.getClass() == FlutterRenderer.class ) { bitmap = ( (FlutterRenderer) this.renderer ).getBitmap();}if(bitmap == null) { Log.println(Log.INFO, TAG, "The bitmap cannot be created :("); return ;}view.setDrawingCacheEnabled(false);iOS能够间接截取蕴含flutter和原生界面的截图。 // iOS截图外围代码 func takeScreenshot(view: UIView, toImageGallery :Bool = true) { let scale :CGFloat = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, scale) view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) let optionalImage :UIImage? = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext()}非凡状况:Android须要截取含有flutter与Native的界面,能够别离独自截取flutter界面和Native界面,获取到两个bitmap,而后做一个bitmap合并,最终失去flutter与native界面的截图 ...

June 21, 2023 · 1 min · jiezi

关于flutter:Flutter状态管理新的实践-京东云技术团队

1 背景介绍1.1 申明式ui申明式UI其实并不是近几年的新技术,然而近几年申明式UI框架十分的炽热。单说挪动端,跨平台计划有:RN、Flutter。iOS原生有:SwiftUI。android原生有:compose。能够看到申明式UI是当前的前端发展趋势。而状态治理是申明式UI框架的重要组成部分。 1.2 申明式UI框架的状态在挪动端之前的命令式UI框架,没有状态的概念。每个控件其实都是无状态的,咱们要更新UI须要手动的去set。命令式UI引入状态的概念,状态能够了解为订阅了控件所依赖数据的变动,当一个控件依赖的数据发生变化时,主动刷新UI展现。最大的劣势就是能够很不便的做到UI和逻辑的解耦。 2 provider状态治理2.1 应用形式定义一个页面如下: []() 实现性能,当点击“按钮”的时候,更新“你好”这个组件 页面局部代码实现(基于StatelessWidget实现): []() model局部实现: []() 2.2 问题和有余点击“按钮”的时候查看页面刷新,发现下表列举的Widget都执行了刷新操作,应用Selector尽管被包裹的内容没有刷新,然而须要进行校验操作。 2.2.1 控件刷新[]() 2.2.2 问题剖析应用不太灵便,想要生产事件刷新UI必须有顶层的Provider提供model,在一些简单场景可能会减少逻辑复杂度状态刷新,不能实现最小粒度的治理代码不够简洁3 新的状态治理形式实际3.1 应用形式实现同样的上述页面逻辑,代码如下(同样基于StatelessWidget实现): 首先不须要依赖内部的provider提供Model,任何想要独立刷新的区域应用TosObWidget控件包裹即可,应用比拟灵便,咱们能够把TosObWidget插入到任何咱们想要的地位(包含provider内),代码逻辑比拟简洁 []() model实现: model的实现更加简洁,不须要继承ChangeNotifier,所以能够把状态数据定义在任何咱们想要的中央,应用.tos扩大属性返回一个蕴含默认值的RxObj对象,当咱们应用set办法更改RxObj的value的时候,告诉依赖此对象的TosObWidget区域进行刷新,例:咱们点击按钮的时候,_model.textA.value = “你好${_model.i++}”,执行后就会刷新依赖textA的TosObWidget(() => Text(_model.textA.value))区域 []() 查看刷新状态(与provider比照): []() 比照发现TosObWidget这种形式,只有依赖的数据发生变化的TosObWidget才会更新状态,能够实现状态刷新粒度最小化,进步性能 3.2 设计思路3.2.1 TosObWidget[]() 首先是应用入口,定义一个TosObWidget控件,入参为build函数,返回widget,每个TosObWidget就是一个可独立进行状态刷新的区域 []() TosObWidget控件的实现如下: []() TosObWidget的build函数为重载的其父类_ObzWidget的build函数,最终会被_ObzWidget的_ObzState调用,_ObzWidget的实现如下: []() 接下来查看_ObzState的实现,次要逻辑都在这个类进行实现,这里贴出所有的代码(留神框起来的逻辑): []() []() 3.2.2 TosObWidget逻辑剖析首先_ObzState依赖一个RxObserver _observer变量RxObserver _observer这个 变量持有了_updateUI()这个办法,最终会通过这个办法刷新TosOBWidget的状态当TosObWidget执行build的时候,会通过一个动态变量RxObserver.proxy把_observer共享进来这样TosObWidget包裹的内容,应用RxObj的getValue的时候会拿到被共享的_observer,这时建设RxObj和TosObWidget的分割分割建设后,重置共享变量RxObserver.proxy这样在RxObj的value执行set办法时,会调用到与其绑定的TosObWidget的_updateUI()这个函数3.2.3 RxObj的实现[]() 如下贴出RxObj的value的get和set函数: 当执行RxObj的value的get办法时,代码如下,拿到 RxObserver的动态成员变量proxy,类型为RxObserver(即为上一步TosObWidget共享进去的_observer)判断RxObserver.proxy不为空,且没有被增加到_observers列表( List _observers),则增加当执行RxObj的value的set办法时,校验value是否与以后的value值雷同,且判断是否是首次创立(首次创立不会执行状态刷新)校验实现后则赋值执行refresh()函数,更新TosObWidget的状态[]() refresh()函数的实现如下: observer.update()函数即为执行与Rxobj关联的TosObWidget的_updateUI()函数: []() 看下RxObserver的实现: 留神框起来的逻辑,update函数即下面_ObzState的_updateUI()函数的援用 []() 至此整个实现流程曾经贯通了,接下来看下如何应用: 1)通过.tos扩大属性定义RxObj变量: []() 2).tos扩大属性的实现如下: []() 3)如果要创立一个默认值为空的,RxObj实例,应用如下形式: ...

June 20, 2023 · 1 min · jiezi

关于flutter:flutter系列之做一个图像滤镜

简介很多时候,咱们须要一些特效性能,比方给图片做个滤镜什么的,如果是h5页面,那么咱们能够很容易的通过css滤镜来实现这个性能。 那么如果在flutter中,如果要实现这样的滤镜性能应该怎么解决呢?一起来看看吧。 咱们的指标在持续进行之前,咱们先来探讨下本章到底要做什么。最终的指标是心愿可能实现一个图片的滤镜性能。 那么咱们的app界面实际上能够分为两个局部。第一个局部就是带滤镜成果的图片,第二个局部就是能够切换的滤镜按钮。 接下来咱们一步步来看如何实现这些性能。 带滤镜的图片要实现这个性能其实比较简单,咱们构建一个widget,因为这个widget中的图片须要依据本身抉择的滤镜色彩来扭转图片的状态,所以这里咱们须要的是一个StatefulWidget,在state外面,存储的就是以后的_filterColor。 构建一个图片的widget的代码能够如下所示: class ImageFilterApp extends StatefulWidget { const ImageFilterApp({super.key}); @override State<ImageFilterApp> createState() => _ImageFilterAppState();}class _ImageFilterAppState extends State<ImageFilterApp> { final _filters = [ Colors.white, ...Colors.primaries ]; final _filterColor = ValueNotifier<Color>(Colors.white); void _onFilterChanged(Color value) { _filterColor.value = value; } @override Widget build(BuildContext context) { return Material( color: Colors.black, child: Stack( children: [ Positioned.fill( child: _buildPhotoWithFilter(), ), ], ), ); } Widget _buildPhotoWithFilter() { return ValueListenableBuilder( valueListenable: _filterColor, builder: (context, value, child) { final color = value; return Image.asset( 'images/head.jpg', color: color.withOpacity(0.5), colorBlendMode: BlendMode.color, fit: BoxFit.cover, ); }, ); }}在build办法中,咱们返回了一个Positioned.fill填充的widget,这个widget能够把app的视图填满。 ...

June 16, 2023 · 3 min · jiezi

关于flutter:flutter系列之做一个会飞的菜单

简介flutter中自带了drawer组件,能够实现通用的菜单性能,那么有没有一种可能,咱们能够通过自定义动画来实现一个别样的菜单呢? 答案是必定的,一起来看看吧。 定义一个菜单我的项目因为这里的次要目标是实现菜单的动画,所以这里的菜单比较简单,咱们的menu是一个StatefulWidget,外面就是一个Column组件,column中有四行诗: static const _menuTitles = [ '迟日江山丽', '春风花草香', '泥融飞燕子', '沙暖睡鸳鸯', ]; Widget build(BuildContext context) { return Container( color: Colors.white, child:_buildContent() ); } Widget _buildContent() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), ..._buildListItems() ], ); } List<Widget> _buildListItems() { final listItems = <Widget>[]; for (var i = 0; i < _menuTitles.length; ++i) { listItems.add( Padding( padding: const EdgeInsets.symmetric(horizontal: 36.0, vertical: 16), child: Text( _menuTitles[i], textAlign: TextAlign.center, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.w500, ), ), ) ); } return listItems; }让menu动起来怎么让menu动起来呢?咱们须要给最外层的AnimateMenuApp增加一个AnimationController,所以须要在_AnimateMenuAppState增加SingleTickerProviderStateMixin的mixin,如下所示: ...

June 6, 2023 · 2 min · jiezi

关于flutter:Flutter-Overlay-的使用-自定义-LoadingToast

背景背景:我的项目中的 Toast 始终试用的是这个包 another_flushbar ,其 Likes 数量还挺多的,然而应用过程中遇到了一些问题,因为这个 Toast 的实现是利用相似 PageRouteBuilder 这样新关上一个路由页面的模式,然而页面中有些组件例如 showDialog、shouBottomSheet 也是应用这种形式,这样就产生了一个问题就是当 Toast 和 dialog 一起应用时当 Toast 呈现 同时和 Dialog 隐没时,路由就会产生抵触,就比拟麻烦。 解决方案:google 了一下发现实现 Toast 更好的办法是应用 Overlay 来自 chatgpt 的答复 在 Flutter 中,Overlay 是一个用于在应用程序中创立和治理覆盖层的组件。它容许你在应用程序的界面上增加或移除覆盖物,并管制它们的显示和地位。Overlay 组件实质上是一个 Stack,它容许你在一个层次结构中搁置多个覆盖物,并依据须要调整它们的程序和地位。每个覆盖物都由 OverlayEntry 来示意,它定义了要在 Overlay 中显示的具体内容。应用 Overlay 和 OverlayEntry,你能够在应用程序的任何中央创立自定义的覆盖物,并将它们搁置在其余组件之上。这对于创立弹出窗口、浮动按钮、告诉栏等交互性或悬浮性的界面元素十分有用。要在应用程序中应用 Overlay,你能够应用 Overlay.of(context) 办法获取以后上下文中的 Overlay。而后,你能够应用 insert 办法将 OverlayEntry 增加到 Overlay 中,并应用 remove 办法将其从 Overlay 中移除。flutter_easyloading在 pub 中找了一下,发现了一个 flutter_easyloading 库,Likes 数量很高,同时反对 loading 和 toast,底层也是应用了 Overlay 实现,但在把它引入我的项目中发现了一些问题: 因为这个库是全局单例,尽管它提供了 loading,toast ,但它的一些自定义配置只能针对一个实例也就说无奈对 loading 和 toast 别离配置色彩什么的 https://github.com/nslogx/flutter_easyloading/issues/188 ,而且该我的项目未解决的 issue 数量特地多不晓得是不是开发者曾经放弃了我发现特地多的 flutter 第三方库,都是会给一些配置选项让开发者自定义款式,但这些配置往往很难满足使用者的需要,其实像 loading 和 toast 这种,第三方库只需提供外围动画,真正要展示的内容让使用者本人传进去就好了,这样的话也就不须要那么多的配置参数了,使用者也能实现本人的需要(flutter 官网的 widget 也是提供了很多配置参数,调试起来很吃力,再次吐槽一下为什么不能只把外围逻辑实现,具体展示交由用户传进去的 widget 来管制)本人利用 Overlay 实现 Toast 、Loading演示成果: ...

June 4, 2023 · 2 min · jiezi

关于flutter:ChatGPT-Flutter快速开发多端聊天机器人App

download:ChatGPT + Flutter疾速开发多端聊天机器人AppJava Web我的项目开发教训分享Java是一门弱小的编程语言,综合使用Java相干技术可能疾速行开发高质量、平安、易保护的Web应用程序。本文将分享咱们在Java Web我的项目开发过程中积攒的教训。 需要剖析在进行任何我的项目开发前,需要剖析是十分重要的一个环节。首先,应该与客户充沛沟通,明确我的项目需要和性能点,并记录入具体的需要文档中。其次,设计的用户界面应该合乎指标用户的应用习惯和界面审美上的需要。最初,依据需要文档以及UI设计稿,设计出数据库和代码构造,为下一步的开发做好筹备。技术选型抉择适合的技术对于我的项目的胜利至关重要。Java Web我的项目开发须要思考到Java自身的个性以及业务逻辑的复杂度等方面。作为一个整体,在技术选型时,应该思考到以下几个因素:零碎的可扩展性和可维护性技术是否成熟且社区沉闷技术是否满足我的项目需要咱们通常会抉择SpringMVC和Spring Boot框架,MyBatis作为ORM框架。以及其余罕用的技术组件,如Tomcat、MySQL、Redis等。 分层设计在Java Web我的项目开发中,分层设计是实现可扩展性和升高耦合度的重要措施。一般而言,咱们将代码划分为体现层、业务层和长久层三个档次。体现层:通常应用SpringMVC框架,对外提供接口服务。业务层:解决零碎中简单的业务逻辑,蕴含业务规定、算法等,能够应用Spring框架来进行Bean的治理。长久层:应用ORM框架实现与数据库的交互,这里咱们抉择应用MyBatis。分层设计使得不同层之间职责清晰,便于模块化开发和保护。 编码标准编码标准是保障团队合作和代码品质的重要伎俩。咱们通常采纳Google Java编程格调指南和阿里巴巴Java开发手册作为编码标准。其中,Google Java格调指南次要关注一些小的语法标准,如命名标准、代码缩进、代码正文等。而阿里巴巴Java开发手册除了根本的编码标准之外

June 2, 2023 · 1 min · jiezi

关于flutter:Flutter三棵树系列之BuildOwner-京东云技术团队

引言Flutter开发中三棵树的重要性显而易见,理解其原理有助于咱们开发出性能更优的App,此文次要从源码角度介绍Element树的治理类BuildOwner。 是什么?BuildOwner是element的治理类,次要负责dirtyElement、inactiveElement、globalkey关联的element的治理。 final _InactiveElements _inactiveElements = _InactiveElements();//存储inactiveElement。final List<Element> _dirtyElements = <Element>[];//存储dirtyElement,就是那些须要重建的element。final Map<GlobalKey, Element> _globalKeyRegistry = <GlobalKey, Element>{};//存储所有有globalKey的element。在哪创立的?BuildOwner是全局惟一的,当然也能够创立一个buildOwner用来治理离屏的widget。其在widgetsBinding的init办法中创立,并在runApp中的attachRootWidget办法中赋值给root element,子element在其mount办法中能够获取到parent的BuildOwner,达到全局应用惟一BuildOwner的成果。 //WidgetsBinding类mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding { @override void initInstances() { super.initInstances(); _instance = this; _buildOwner = BuildOwner();//创立buildOwner buildOwner!.onBuildScheduled = _handleBuildScheduled;//赋值buildScheduled办法 // ... }}//Element类的mount办法void mount(Element? parent, Object? newSlot) { //... _parent = parent; _depth = _parent != null ? _parent!.depth + 1 : 1; if (parent != null) { //当parent为null时,这个element必定是root element, //root element的buildOwner是在runApp中调用assignOwner办法赋值的。 _owner = parent.owner;//与parent专用一个buildOwner } //... }dirtyElements的治理增加增加操作次要用的是BuildOwner的scheduleBuildFor办法,当你应用State类时,一个残缺的链条如下: ...

May 30, 2023 · 3 min · jiezi

关于flutter:Flutter调优深入探究MediaQuery引起界面Rebuild的原因及解决办法-京东云技术团队

前言咱们能够通过MediaQuery.of(context)办法获取到一些设施和零碎的相干信息,比方状态栏的高度、以后是否是光明模式等等,应用起来相当不便,然而也要留神可能引起的页面rebuild问题。本文会介绍一个典型的例子,并深刻源码来探讨引起rebuild的起因,最初介绍防止rebuild的几个方法。 典型例子以快递App中的查快递场景举例,首页用MediaQuery.of(context).padding.top获取了状态栏高度,用户点击“查快递”按钮会跳转到查快递界面,在查快递界面,用户输出单号可进行查问操作。 \当首页的build办法被调用时,会输入咱们提前加好的日志。咱们发现,当查快递界面的键盘弹出时,首页的build办法被调用了屡次: 主界面的build代码如下: 源码探索既然是因为主界面在build办法里应用了MediaQuery.of(context),从而导致当键盘弹出/暗藏时进行rebuild操作,那么就先来看下MediaQuery类。 MediaQuery 其继承自InheritedWidget,本身并没有重写createElement办法,从flutter三棵树的角度讲,对应的Element即为InheritedElement。有两个属性,data和child,咱们能够从data中获取一些设施/零碎相干的属性。 另外还有两个比拟重要的办法: fromWindow(key : Key, child : Widget) 此办法间接返回_MediaQueryFromWindow对象,前面会具体介绍。 of(context : BuildContext) 办法里调用了dependOnInheritedWidgetOfExactType,接下来咱们详细分析下背地的调用流程。 MediaQuery.of(context) 调用流程入参是context,本例中的主界面是StatelessWidget,那么这里的context便是StatelessElement。整体调用流程如下: dependOnInheritedWidgetOfExactType 从_inheritedWidgets列表中查问是否有MediaQuery类型的InheritedElement,从三棵树的角度讲,就是从以后节点始终向上查找,找到最近的MediaQuery控件。如果找到,则调用dependOnInheritedElement办法(个别状况下是肯定能找到的,上面再具体介绍)。 dependOnInheritedElement 此办法负责将找到的InheritedElement(也就是MediaQuery对应的Element)存起来,并且调用InheritedElement#updateDependencies办法。 updateDependencies setDependencies 最初两个办法很简略,其作用是将主页对应的StatelessElement存储到了MediaQuery对应的InheritedElement#_dependents中。 钻研完MediaQuery.of(context)背地的原理,咱们能够晓得:通过调用of办法,主界面对应的Element和MediaQuery建设了绑定关系,MediaQuery对应的InheritedElement存储了主界面Element的援用。 Rebuild终点当介绍dependOnInheritedWidgetOfExactType办法时,咱们提道:从以后节点往父节点寻找,个别状况下是肯定能找到的MediaQuery控件的。这是因为在WidgetsApp里会主动给咱们创立一个根MediaQuery。 在main办法里,无论应用CupertinoApp还是MaterialApp,最初都会在外部创立WidgetsApp。咱们间接看_WidgetsAppState#build办法里的一个代码片段: 会首先查看widget.useInheritedMediaQuery,这个属性默认为false。如果你创立MaterialApp/CupertinoApp时,没有设置useInheritedMediaQuery属性,或者设置了这个属性为null,但找不到MediaQueryData,那么这里就会调用MediaQuery.fromWindow办法。 下面介绍MediaQuery#fromWindow时,咱们晓得它会创立_MediaQueryFromWindow控件。 _MediaQueryFromWindow的代码不是很多,把和本文相干的代码全副贴出来了,大家能够本人看下,代码如上图所示。 build办法里创立了MediaQuery控件,并实现了didChangeMetrics办法,当手机产生旋转、键盘弹出/暗藏时就会调用此办法,didChangeMetrics外部又调用了setSate,从而导致build办法被从新调用。 通过flutter三颗树的原理咱们能够晓得,上述所说的“build办法被从新调用”波及到MediaQueryFromWindow对应的Element的updateChild办法,简略看下updateChild的外部解决规定: 对MediaQueryFromWindow而言,每次都会创立新的MediaQuery Widget,依据Element#updateChild源码(不是本文探讨重点,不再详细分析其源码)得悉,最终会调用MediaQuery对应的Element的update办法。 通过一系列的跳转过后,最终会调用到上面的两个外围办法: 下面介绍的MediaQuery.of(context)办法最终会把入参Context放到_dependents变量里,而这里会遍历这个map,调用每一个Context的didChangeDependecies办法,didChangeDependecies会将此Context置为dirty状态,下一帧来长期会被从新绘制,并调用此Context的build办法。 所以,破案了,当键盘弹起/暗藏时快递主页会被rebuild的起因找到了! 整体的rebuild调用流程如下,感兴趣的能够联合这个调用流程图去看源码: 防止rebuild的方法钻研过源码后,解决方案就变的很简略。 自定义useInheritedMediaQuery属性为true,并在最外面包一层MediaQuery,让WidgetsApp创立时应用MediaQuery,而不去应用监听了application尺寸变动的_MediaQueryFromWindow控件。 防止在页面中应用MediaQuery.of(context)办法,能够应用对应的代替办法,比方本例能够采纳上面的代码进行代替,留神单位的转换。 如果必须要应用MediaQuery.of(context)办法,能够应用Builder控件包裹下,of办法的入参传入此Builder的context即可,这样被rebuild仅是Builder控件包裹下的widget子树。 总结app界面逐步简单时,咱们不得不思考去优化界面性能。本文中介绍的例子在开发中是很常见的,如果不理解MediaQuery.of的机制,可能会引起大量应用此办法的界面产生重绘操作,造成页面卡顿、帧率降落。咱们详细分析了背地的源码逻辑,介绍了解决办法,心愿能给大家的调优工作提供些许帮忙。 作者:京东物流 沈亮堂 起源:京东云开发者社区

May 29, 2023 · 1 min · jiezi

关于flutter:Google-IO-2023-推出Flutter-310-快来看看都有哪些变化

本文首发自[慕课网] ,想理解更多IT干货内容,程序员圈内热闻,欢送关注"慕课网"及“慕课网公众号”!   作者:   CrazyCodeBoy |慕课网名师 往年的Google I/O满满的 AI与狠活,而且还推出 Flutter 3.10,接下来就让我带你一起来看看 Flutter 3.10都有哪些变动吧! 首先看此次更新的亮点:     公布了Dart 3,并引入到 Flutter 3.10中;     iOS 默认应用了 Impeller;     Material更新到了M3版本,并且很多控件在M3版本下都有更新;     Web 能够无iframe 嵌套到其余利用; 另外, Flutter 3.10还包含许多Web、挪动端、图形、平安等方面的改良。 引擎(Engine)方面的更新Impeller在3.7稳固版本中,Flutter官网在iOS上预览了Impeller。自那时以来,Flutter官网收到了许多用户的贵重反馈,并加以解决。在此版本中,Impeller有超过250个提交,Flutter官网将Impeller设为iOS上的默认渲染器。应用Flutter3.10构建的所有iOS利用默认应用Impeller。这些iOS利用将具备更少的卡顿和更稳固的性能。 自3.7版本以来,Impeller在iOS上改善了其内存占用。Impeller应用更少的渲染通道和两头渲染指标。在较新的iPhone上,启用有损纹理压缩能够减小内存占用,而不影响保真度。这些改良也显著进步了iPad的性能。 以"Wonderous"利用中的"pull quote"屏幕为例。这些改良将简直缩小了这些屏幕的一半内存占用。缩小内存应用还使GPU和CPU的负载略微升高。"Wonderous"利用可能无奈察觉到负载的升高。之前它的帧曾经在估算范畴内渲染,但这一变动应缩短电池的使用寿命。 Impeller还可能更快地实现受欢迎的性能申请。其中一个例子是在iOS上反对更宽泛的P3色调范畴。无关该性能的形容,请查看本文的其余局部。 社区的奉献放慢了Flutter官网的停顿,尤其是GitHub用户ColdPaleLight和luckysmg。他们编写了多个与Impeller相干的补丁,进步了保真度和性能。 尽管Impeller满足了大多数Flutter利用的渲染需要,但你能够抉择退出Impeller。如果抉择退出,请思考在GitHub上提交问题,通知Flutter官网起因。利用用户可能会留神到Skia和Impeller在渲染方面存在轻微差别。这些差别可能是谬误,因而请不要犹豫提交问题。在将来的版本中,Flutter官网将删除iOS上的旧版Skia渲染器,以减小Flutter的大小。 Impeller的Vulkan后端仍在继续开发中。Impeller在Android上仍处于踊跃开发阶段,但尚未筹备好进行预览。Flutter官网打算在不久的未来分享更多相干内容。 要理解Flutter官网的停顿,请查看Flutter官网的GitHub我的项目板。 与性能(Performance)无关的更新3.10版本除了Impeller之外,还蕴含了更多性能改良和修复。 打消卡顿Flutter官网要感激开源贡献者luckysmg。他们发现能够从Metal驱动程序中缩小获取下一个可绘制层的工夫。要取得此劣势,你须要将FlutterViews的背景色彩设置为非空值。这个扭转打消了在最新的iOS 120Hz显示器上的低帧率问题。在某些状况下,帧率进步了三倍。这帮忙Flutter官网解决了六个以上的GitHub问题。这个扭转十分重要,Flutter官网将一个修复补丁回溯到了3.7版本中。 在3.7稳定版中,Flutter官网将本地图片的加载从平台线程移到Dart线程,以防止提早平台线程的vsync事件。然而,用户留神到这个在Dart线程上的额定工作也引起了一些卡顿问题。在此版本中,Flutter官网将本地图片的关上和解码从Dart线程移到了后盾线程。这个扭转打消了在具备大量本地图片的屏幕上可能呈现的长时间暂停,同时防止了提早vsync事件。在Flutter官网的本地测试和自动化基准测试中,这个扭转将多个同时加载的图片的加载工夫缩短了一半。 Flutter官网持续在Flutter的新外部DisplayList构造之上构建优化。在此版本中,Flutter官网增加了基于R-Tree的剔除机制。该机制在渲染器中更早地删除绘制操作的解决。这个优化减速了,例如,一个输入在屏幕外的自定义绘制器的渲染。Flutter官网的微基准测试显示,DisplayList解决工夫缩小了多达50%。具备裁剪的自定义绘制器的改良成果可能会有所不同。改良水平取决于暗藏绘制操作的复杂性和数量。 缩小iOS启动提早在利用程序包中进行标识符查找的低效策略减少了应用程序的启动提早。这个启动提早与应用程序的大小成比例增长。在此版本中,Flutter官网修复了利用程序包标识符查找的问题。这将大型生产应用程序的启动提早缩小了100毫秒,约为30-50%。 减小体积Flutter默认应用SkParagraph作为文本成型、布局和渲染的默认库,Flutter官网增加了一个标记以回退到传统的libtxt和minikin库。因为Flutter官网对SkParagraph有充沛的信念,所以在此版本中Flutter官网移除了libtxt和minikin及其标记。这将减小Flutter的压缩大小约30KB。 稳定性在3.0版本中,Flutter官网在渲染流程的前期启用了一项Android性能。这个Android性能应用了高级GPU驱动程序性能。当只有一个“脏”区域发生变化时,这些驱动程序性能只会从新绘制屏幕的较少部分。Flutter官网通过晚期的优化和相似成果的图形流水线进一步改良了这一点。只管Flutter官网的基准测试后果激励Flutter官网这么做,但呈现了两个问题。首先,最大改良的基准测试可能不能代表理论应用状况。其次,反对此GPU驱动程序性能的设施和Android版本的范畴证实很难找到。思考到停顿无限并且反对无限,Flutter官网在Android上禁用了局部从新绘制性能。 在Skia后端上,此性能在iOS上依然启用。Flutter官网预计在将来的版本中与Impeller一起启用它。 两个API改良在Flutter 3.10中APNG解码器与图像加载API有所改进。 APNG解码器Flutter 3.10解决了Flutter官网最受关注的问题之一。它减少了对APNG图像的解码能力。你能够应用Flutter现有的图像加载API加载APNG图像。 图像加载API改良Flutter备受尊敬的工程总监tvolkert对dart:ui的图像加载API进行了改良。Flutter官网增加了一个新办法instantiateImageCodecWithSize。它反对以下三个条件的图像加载用例: 加载时纵横比未知有边界框束缚原始纵横比束缚例如,当应用程序尝试从一组可能性中从网络加载并显示一张图片时。 与挪动端(Mobile)无关的更新iOS无线调试 当初,你能够在不应用数据线的状况下运行和热重载Flutter iOS应用程序了!在胜利将iOS设施与Xcode进行无线配对后,你能够应用flutter run命令将应用程序部署到该设施上。如果遇到问题,请确保Window > Devices和Simulators > Devices下显示了设施旁边的网络图标。要理解更多信息,请查看Flutter官网的文档。 宽色域图像反对 当初,iOS上的Flutter利用能够反对对宽色域图像进行精确渲染。要应用宽色域反对,应用程序必须应用Impeller,并在Info.plist文件中增加FLTEnableWideGamut标记。 拼写查看反对 ...

May 26, 2023 · 2 min · jiezi

关于flutter:Flutter热更新技术探索-京东云技术团队

一,需要背景:APP公布到市场后,难免会遇到重大的BUG妨碍用户应用,因而有在不公布新版本APP的状况下应用热更新技术立刻修复BUG需要。原生APP(例如:Android & IOS)的热更新需要曾经比拟成熟,但Flutter技术栈目前还短少相似的技术计划,因而Flutter研发团队,也须要相似的热更新技术。 二,Flutter热更新技术方向剖析:通过剖析目前可能有三种可行的计划: 1)相似RN框架; 2)页面动静组件框架; 3)Dart虚拟机定制计划; 计划名称原理长处毛病开源计划相似RN的计划用JS以Flutter语法写dart,而后用JavaScript把XML DSL转为Flutter的原子widget组件,而后再让Flutter来渲染因为ios零碎内置反对js,ios上齐全能够实现更新1)因为跨语言执行,对于性能有影响;学习老本高 2)Android 端须要额定引入JS库手Q的MXFlutter,58同城的Fair页面动静组件计划编译期时插桩/预埋好DynamicWidget到代码中,而后动静下发Json 数据,通过协定好的语义匹配到JSON内的数据,动静替换Widget内容来实现更新能反对Android/iOS 两端的更新1)UI更新绝对较容易,业务逻辑动态化较麻烦; 2)语义解析器开发成本绝对较大,且不易保护 3)须要一整套前后端服务和工具天猫的Tangram,淘宝的DinamicX等Dart虚拟机定制计划通过剖析Dart虚拟机的原理,批改Flutter Engine层Java/C++代码实现热更新的指标;性能影响小,动态性很高,技术上能够替换所有Flutter页面(包含UI,逻辑,资源文件)因为应用的是定制引擎,须要保护不同版本的Flutter引擎代码;未开源因为其余形式都有开源的示例,本案将重点以第三种“Dart虚拟机定制计划”为指标,做计划的钻研解说。 三,准备常识在开始理解技术计划之前,须要提前理解一些相应的技术概念: 3.1 Flutter编译模式Flutter开发语言是Dart,它的编译模式来自Dart的编译模式,次要有JIT(Just In Time)和AOT(Ahead Of Time)。 编译模式名称特点长处毛病JIT即时编译,典型例子V8,它能够即时编译运行JS,只须要输出源代码字符串,就能够编译运行代码能够动静下发和执行代码,不必管CPU架构,能够提供动态化内容1,大量字符串代码让JIT编译器破费工夫和内存; 2,性能不好;AOT事后编译,典型例子C/C++,通过GCC编译成二进制代码,而后装置获得权限后才能够加载执行当时编译好的,加载和执行速度快1,编译时辨别CPU架构; 2,生成的二进制代码包比拟大; 3,二进制代码须要获得权限才能够执行,无奈在ios零碎上动静更新Flutter编译模式有:Debug,Release,Profile; Flutter编译模式特点Debug对应JIT模式,反对设施和模拟器; 关上了断言,反对疾速开发,反对HotReload; 并未对包大小,执行速度做优化;Release对应AOT模式,反对真机,不反对模拟器; 禁止了所有断言调试信息; 对包大小,启动和执行速度进行了优化;Profile相似Release模式,保留了一些调试性能,帮忙性能剖析;3.2 Flutter编译产物剖析Flutter下的iOS/Android工程实质上是一个规范的iOS/Android的工程;IOS平台: Flutter通过在BuildPhase中增加shell(xcode\_backend.sh)来生成和嵌入App.framework和Flutter.framework到ios; Android平台: Flutter通过gradle来增加flutter.jar和编译完的二进制文件增加到Android; 3.2.1 引擎层构造剖析: 3.2.2 Android编译产物的剖析 3.2.3 IOS编译产物的剖析 四,热更新技术计划剖析4.1 业务代码剖析依据“3.3.1” ~“3.3.2”的剖析能够确定无论是IOS还是Android APP业务代码都是由四个段组成:kDartVmSnapshotData、kDartVmSnapshotInstructions、kDartIsolateSnapshotData、kDartIsolateSnapshotInstructions;实践上只有能动静替换加载的代码段&数据段代码即可实现目标。 名称正文作用正文kDartIsolateSnapshotDataDart isolate数据段类信息,全局变量,函数指针等容许动静下发kDartIsolateSnapshotInstructionsDart isolate指令段蕴含由Dart isolate执行的AOT代码IOS不容许动静下发kDartVmSnapshotDatavm isolate数据段isolate 之间共享的 Dart 堆 (heap) 的初始状态容许动静下发kDartVmSnapshotInstructionsvm isolate指令段蕴含 VM 中所有 Dart isolate 之间共享的通用程序的 AOT 指令IOS不容许动静下发正文: isolate, snapshot, vm isolate含意解释如下: ...

May 26, 2023 · 1 min · jiezi

关于flutter:flutter系列之做一个下载按钮的动画

简介咱们在app的开发过程中常常会用到一些示意进度类的动画成果,比方一个下载按钮,咱们心愿按钮可能动态显示下载的进度,这样能够给用户一些直观的印象,那么在flutter中一个下载按钮的动画应该如何制作呢? 一起来看看吧。 定义下载的状态咱们在真正开发下载按钮之前,首先定义几个下载的状态,因为不同的下载状态导致的按钮展现样子也是不一样的,咱们用上面的一个枚举类来设置按钮的下载状态: enum DownloadStatus { notDownloaded, fetchingDownload, downloading, downloaded,}基本上有4个状态,别离是没有下载,筹备下载然而还没有获取到下载的资源链接,获取到下载资源正在下载中,最初是下载结束。 定义DownloadButton的属性这里咱们须要自定义一个DownloadButton组件,这个组件必定是一个StatelessWidget,所有的状态信息都是由内部传入的。 咱们须要依据下载状态来指定DownloadButton的款式,所以须要一个status属性。下载过程中还有一个下载的进度条,所以咱们须要一个downloadProgress属性。 另外在点击下载按钮的时候会触发onDownload事件,下载过程中能够触发onCancel事件,下载结束之后能够登程onOpen事件。 最初因为是一个动画组件,所以还须要一个动画的持续时间属性transitionDuration。 所以咱们的DownloadButton须要上面一些属性: class DownloadButton extends StatelessWidget { ... const DownloadButton({ super.key, required this.status, this.downloadProgress = 0.0, required this.onDownload, required this.onCancel, required this.onOpen, this.transitionDuration = const Duration(milliseconds: 500), });让DownloadButton的属性能够动态变化下面提到了DownloadButton是一个StatelessWidget,所有的属性都是由内部传入的,然而对于一个动画的DownloadButton来说,status,downloadProgress这些信息都是会动态变化的,那么怎么能力让变动的属性传到DownloadButton中进行组件的重绘呢? 因为波及到简单的状态变动,所以简略的AnimatedWidget曾经满足不了咱们的需要了,这里就须要用到flutter中的AnimatedBuilder组件了。 AnimatedBuilder是AnimatedWidget的子类,它有两个必须的参数,别离是animation和builder。 其中animation是一个Listenable对象,它能够是Animation,ChangeNotifier或者等。 AnimatedBuilder会通过监听animation的变动状况,来从新构建builder中的组件。buidler办法能够从animation中获取对应的变动属性。 这样咱们创立一个Listenable的DownloadController对象,而后把DownloadButton用AnimatedBuilder封装起来,就能够实时监测到downloadStatus和downloadProgress的变动了。 如下所示: Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('下载按钮')), body: Center( child: SizedBox( width: 96, child: AnimatedBuilder( animation: _downloadController, builder: (context, child) { return DownloadButton( status: _downloadController.downloadStatus, downloadProgress: _downloadController.progress, onDownload: _downloadController.startDownload, onCancel: _downloadController.stopDownload, onOpen: _downloadController.openDownload, ); }, ), ), ), ); }定义downloadControllerdownloadController是一个Listenable对象,这里咱们让他实现ChangeNotifier接口,并且定义了两个获取下载状态和下载进度的办法,同时也定义了三个点击触发事件: ...

May 24, 2023 · 2 min · jiezi

关于flutter:Flutter三棵树系列之详解各种Key-京东云技术团队

简介key是widget、element和semanticsNode的惟一标识,同一个parent下的所有element的key不能反复,然而在特定条件下能够在不同parent下应用雷同的key,比方page1和page2都能够应用ValueKey(1) 。 罕用key的UML关系图如上,整体上key分为两大类-LocalKey和GlobalKey,这两个key都是抽象类,LocalKey的实现类有 ValueKey、ObjectKey和UniqueKey,GlobalKey实现类有LabeledGlobalKey和GlobalObjectKey。 Key@immutableabstract class Key { const factory Key(String value) = ValueKey<String>; @protected const Key.empty();}Key是所有key的基类,外部实现了一个工厂构造函数,默认创立String类型的ValueKey。外部还是先了一个empty的构造函数,次要是给子类用的。 LocalKeyabstract class LocalKey extends Key { const LocalKey() : super.empty();}LocalKey没有理论作用,次要是用来辨别GlobalKey的,其具体的实现类有ValueKey、ObjectKey、UniqueKey。 ValueKeyclass ValueKey<T> extends LocalKey { const ValueKey(this.value); final T value; @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; return other is ValueKey<T> && other.value == value; } @override int get hashCode => hashValues(runtimeType, value);外部保护了泛型类型的value属性,并实现了==和hashCode办法。只有两个ValueKey的value属性相等,那么就认为两个Key相等。 ObjectKeyclass ObjectKey extends LocalKey { const ObjectKey(this.value); final Object? value; @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; return other is ObjectKey && identical(other.value, value); } @override int get hashCode => hashValues(runtimeType, identityHashCode(value));ObjectKey是继承自LocalKey的,能够将其了解成泛型类型为Object的ValueKey。然而留神两者的==办法是不一样的,ValueKey依据value的值是否相等来判断ValueKey是否相等(相当于java的equals办法),而ObjectKey依据indentical办法(判断两个援用是否指向同一个对象,相当于java的==操作符)来判断两个ObjectKey是否相等的。 ...

May 24, 2023 · 2 min · jiezi

关于flutter:flutter系列之使用AnimationController来控制动画效果

简介之前咱们提到了flutter提供了比较简单好用的AnimatedContainer和SlideTransition来进行一些简略的动画成果,然而要齐全实现自定义的简单的动画成果,还是要应用AnimationController。 明天咱们来尝试应用AnimationController来实现一个拖拽图片,而后返回原点的动画。 构建一个要动画的widget在本文的例子中,咱们心愿可能让一个图片能够实现拖拽而后主动返回原来地位的成果。 为了实现这个性能,咱们首先构建一个放在界面两头的图片。 child: Align( alignment: Alignment.center, child: Card( child: Image(image: AssetImage('images/head.jpg')) ), )这里应用了Align组件,将一个图片对象放在界面两头。 接下来咱们心愿这个widget能够拖拽,那么把这个child放到一个GestureDetector中,这样就能够相应拖拽对应的响应。 Widget build(BuildContext context) { final size = MediaQuery.of(context).size; return GestureDetector( onPanUpdate: (details) { setState(() { _animateAlign += Alignment( details.delta.dx / (size.width / 2), details.delta.dy / (size.height / 2), ); }); }, child: Align( alignment: _animateAlign, child: Card( child: widget.child, ), ), ); }为了能实现拖动的成果,咱们须要在GestureDetector的onPanUpdate办法中对Align的地位进行批改,所以咱们须要调用setState办法。 在setState办法中,咱们依据手势的地位来调整Alignment的地位,所以这里须要用到MediaQuery来获取屏幕的大小。 然而当初实现的成果是图像随手势挪动而挪动,咱们还须要实现在手放开之后,图像主动回复到原来地位的动画成果。 让图像动起来因为这次须要变动的是Alignment,所以咱们先定义一个蕴含Alignment的Animation属性: late Animation<Alignment> _animation;接下来咱们须要定义一个AnimationController,用来管制动画信息,并且指定咱们须要的动画终点和起点: late AnimationController _controller; _animation = _controller.drive( AlignmentTween( begin: _animateAlign, end: Alignment.center, ), );咱们动画的终点地位就是以后image所在的Alignment,起点就在Alignment.center。 ...

May 17, 2023 · 1 min · jiezi

关于flutter:Google-应用出海计划-指南针-第六期强势回归启动报名

May 10, 2023 · 0 min · jiezi

关于flutter:Flutter常用状态管理框架及优缺点

Flutter 中常见的状态治理框架有以下几种: Provider: Provider 是一个轻量级的状态治理框架,可用于单个 Widget 或整个 Widget 树中散发状态。它通过 InheritedWidget 和 ChangeNotifier 来实现状态治理,并反对依赖项注入。Redux: Redux 库是将状态和业务逻辑从 UI 中清晰拆散的一种形式。它通过一个繁多的状态存储库来管理应用程序的状态,并应用可预测的形式批改状态。MobX: MobX 是一种基于响应式编程的状态治理框架,它应用观察者模式来察看和响应状态的变动,并能够主动地更新 UI。BLoC: BLoC 是一种基于 Reactive Programming 和 Stream 的状态管理模式,它将应用程序的状态分为三层:Business Logic、View 和 UI。Business Logic 层负责逻辑解决,View 层负责渲染,UI 层则负责响应用户的操作。GetX: GetX 是一个轻量级的状态治理框架,提供了路由、依赖注入、状态治理等性能,通过依赖注入和动态扩大,让您能更加不便地构建构造清晰、易于保护的架构。以下是上述框架的优缺点比照: 框架长处毛病Provider简略易用,轻量级;反对依赖项注入;方便快捷的状态治理难以解决大型利用中的简单状态;不反对异步操作;共享状态跨 widget 树Redux独立的状态治理,不便对立和治理;可预测且容易测试;反对中间件,不便解决异步操作学习老本较高;可能存在大量的样板代码;对于小型利用过于简单MobX响应式编程,易于了解和应用;自动化生成代码,方便快捷;扩展性很强状态扩散,可能难以把握利用的状态流;可能存在过多的正文和无用代码;须要加注解,使代码变得繁琐BLoC实用于大型利用;标准的模式,不便保护;反对异步操作减少了代码复杂度;学习老本略高GetX简略易用,轻便;提供残缺的路由、依赖注入等性能;反对响应式编程在大型利用中,可能会难以治理依赖关系;响应式编程可能导致性能问题综上所述,抉择适宜本人我的项目的Flutter状态治理框架十分重要。 最初,小伙伴们我的项目中你们用的是哪个框架呀? 主题:Flutter状态治理框架的抉择 投票选项: ProviderReduxMobXBLoCGetX 请在上面评论区进行投票留言哦。

May 9, 2023 · 1 min · jiezi

关于flutter:flutter系列之做一个修改组件属性的动画

简介什么是动画呢?动画实际上就是不同的图片间断起来造成的。flutter为咱们提供了一个AnimationController来对动画进行详尽的管制,不过间接是用AnimationController是比较复杂的,如果只是对一个widget的属性进行批改,能够做成动画吗? 答案是必定的,一起来看看吧。 flutter中的动画widget如果你只是心愿动画展现widget的属性的变动,比方比方长度,高度,宽度或者色彩等进行动态变化,那么能够间接应用flutter提供的AnimatedContainer。 先来看下AnimatedContainer的定义: class AnimatedContainer extends ImplicitlyAnimatedWidgetAnimatedContainer继承自ImplicitlyAnimatedWidget,什么是ImplicitlyAnimatedWidget呢?翻译过去就是隐式的动画widget。 这个widget会主动依据widget属性的变动生成对应的动画。在应用上十分的简略。 AnimatedContainers应用举例AnimatedContainer是一个container,所以它能够蕴含child属性,然而AnimatedContainer的动画只是针对容器自身来说的,动画并不会利用到它的child中。 所以为了展现widget自身的变动,咱们能够给widget设置一个BoxDecoration,设置它的色彩跟borderRadius。 如下所示: body: Center( child: AnimatedContainer( width: 200, height: 200, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10), ), duration: const Duration(seconds: 1), curve: Curves.easeInBack, ), )下面的代码会在界面上展现一个长度和宽度都等于200的Container,它的背景是blue,还有一个圆形的borderRadius。 并且咱们定义了动画的duration和变动曲线的形式。 接下来咱们只须要在setState办法中对AnimatedContainer中的属性进行变动,就会主动触发动画成果。 为了实现这个动画的性能,咱们须要把width,height等属性用动静变量存储起来,这样才能够在setState的时候对属性进行变动。 咱们将这些属性放在一个StatefulWidget的State中: double _width = 100; double _height = 100; Color _color = Colors.blue; BorderRadiusGeometry _borderRadius = BorderRadius.circular(10);这样咱们在build办法中应用下面定义的属性: body: Center( child: AnimatedContainer( width: _width, height: _height, decoration: BoxDecoration( color: _color, borderRadius: _borderRadius, ), duration: const Duration(seconds: 1), curve: Curves.easeInBack, ), )而后在floatingActionButton的onPressed中批改这些属性,从而实现widget属性变动的动画性能: ...

May 9, 2023 · 1 min · jiezi

关于flutter:Flutter出现CocoaPods报错的情况Mac和IOS

谬误状况: Launching lib/main.dart on iPad Pro (12.9-inch) (5th generation) in debug mode...main.dart:1CocoaPods' output:↳ Preparing Analyzing dependencies Inspecting targets to integrate Using `ARCHS` setting to build architectures of target `Pods-Runner`: (``) Finding Podfile changes A image_editor_dove - Flutter - file_picker - flutter_image_compress - flutter_secure_storage - image_gallery_saver - image_picker_ios - path_provider_foundation - sqflite Fetching external sources -> Fetching podspec for `Flutter` from `Flutter` -> Fetching podspec for `file_picker` from `.symlinks/plugins/file_picker/ios` -> Fetching podspec for `flutter_image_compress` from `.symlinks/plugins/flutter_image_compress/ios` -> Fetching podspec for `flutter_secure_storage` from `.symlinks/plugins/flutter_secure_storage/ios` -> Fetching podspec for `image_editor_dove` from `.symlinks/plugins/image_editor_dove/ios` [!] No podspec found for `image_editor_dove` in `.symlinks/plugins/image_editor_dove/ios` /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/external_sources/path_source.rb:14:in `block in fetch' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/user_interface.rb:64:in `section' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/external_sources/path_source.rb:11:in `fetch' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer/analyzer.rb:997:in `fetch_external_source' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer/analyzer.rb:976:in `block (2 levels) in fetch_external_sources' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer/analyzer.rb:975:in `each' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer/analyzer.rb:975:in `block in fetch_external_sources' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/user_interface.rb:64:in `section' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer/analyzer.rb:974:in `fetch_external_sources' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer/analyzer.rb:118:in `analyze' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer.rb:422:in `analyze' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer.rb:244:in `block in resolve_dependencies' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/user_interface.rb:64:in `section' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer.rb:243:in `resolve_dependencies' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/installer.rb:162:in `install!' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/command/install.rb:52:in `run' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/claide-1.1.0/lib/claide/command.rb:334:in `run' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/lib/cocoapods/command.rb:52:in `run' /Users/shixin/.rvm/rubies/ruby-2.7.2/lib/ruby/gems/2.7.0/gems/cocoapods-1.12.0/bin/pod:55:in `<top (required)>' /usr/local/bin/pod:23:in `load' /usr/local/bin/pod:23:in `<main>' /Users/shixin/.rvm/rubies/ruby-2.7.2/bin/ruby_executable_hooks:22:in `eval' /Users/shixin/.rvm/rubies/ruby-2.7.2/bin/ruby_executable_hooks:22:in `<main>'这种状况,首先在终端cd进入到Flutter我的项目相应的ios或者mac目录下 ...

April 25, 2023 · 1 min · jiezi

关于flutter:Flutter-中检测常用命令

查看ruby的版本 ruby -v查看rvm 版本 rvm -v查看源 gem sources -l移除源 gem sources --remove https://rubygems.org/切换源 gem sources --add https://gems.ruby-china.com/查看pod版本 pod --version

April 24, 2023 · 1 min · jiezi

关于flutter:App复杂动画实现Rive保姆级教程-京东云技术团队

作者:京东物流 沈亮堂 在App开发过程中,如果想实现动画成果,能够粗略分为两种形式。一种是间接用代码编写,像平移、旋转等简略的动画成果,都能够这么干,如果略微简单点,就会对开发工程师的数学功底、图形图像学功底有很高的要求。 另一种形式,能够让UI同学配合,一次性出多张图片或者间接出一张GIF图,通过短时间内疾速轮播图片的形式来实现简单动画成果,这种形式真正实现起来还是有挺多问题的,比方短少对动画过程的管制、图片尺寸的适配等等。那么,有没有更好的解决方案呢? 有的,Rive。 简介Rive是专门为简化动画的实现而生的,设计师能够在其官网通过利落拽实现各种简单动画成果,设计结束后导出动画文件,工程师能够在App里间接导入此文件,配合相应的SDK即可实现。 其官网有具体的开发文档,同时也有本人的社区资源,咱们能够间接从社区里下载他人设计好的动画成果进行学习。另外特地重要的是,Rive反对跨平台,同时反对Android、iOS、Flutter、JS、React、C++等等,本文以Flutter的实现为例介绍。 一个残缺的例子登陆Rive官网进行设计,并导出相应的动画文件,Rive的动画文件是以.riv结尾。本文示例是从官网的社区里找的一个集体比拟喜爱的动效。顺次运行上面的命令,引入rive sdk。 将导出的.riv文件放到资源目录下,并批改pubspec.yaml文件。 加载动画文件并展现的外围代码: 外围代码就这么多,对于代码中的标注具体阐明下: 标注1的中央,次要作用是获取状态机控制器,fromArtboard 办法有两个参数,第二个参数是状态机的名称,这个名称须要和UI同学协商好,一旦确定好名称就不容许设计同学再改了,对应于设计面板界面的左下角,如下图: 标注2的中央,本例的动画是依据“数值”的变动而变动的,findInput的入参同样须要和UI同学协商好,一旦设计时把这个名字改了,代码里也别忘了进行相应的批改,也在设计面板的左下角,在状态机名称的左边,如下图: 残缺的代码如下,大家能够按步骤本人操作体验下。 class RiveDemo extends StatefulWidget { const RiveDemo({Key? key}) : super(key: key); @override State<RiveDemo> createState() => _RiveDemoState();}class _RiveDemoState extends State<RiveDemo> { /// 状态机控制器 StateMachineController? controller; /// 管制输出数值 SMIInput<double>? valueController; ///画板,配合Rive widget 应用,展现动画成果。 Artboard? riveArtboard; Timer? timer; @override void initState() { super.initState(); //加载 rootBundle.load('asset/rives/rive_demo.riv').then((value) async { final file = RiveFile.import(value); final artboard = file.mainArtboard; //1 controller = StateMachineController.fromArtboard(artboard, 'TreeMachine'); if (controller != null) { setState(() { artboard.addController(controller!); //2 valueController = controller!.findInput('input'); valueController!.value = -4; }); } riveArtboard = artboard; }); } @override void dispose() { controller?.dispose(); stopAnimation(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Rive Demo'), ), backgroundColor: Colors.white, body: Center( child: riveArtboard == null ? const CircularProgressIndicator() : Rive(artboard: riveArtboard!), ), floatingActionButton: SizedBox( height: 50, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { startAnimation(); }, child: const Text('start'), ), TextButton( onPressed: () { stopAnimation(); }, child: const Text('stop'), ), TextButton( onPressed: () { resetAnimation(); }, child: const Text('reset'), ), ], ), ), ); } /// 开始动画 void startAnimation() { if (timer != null) { return; } timer = Timer.periodic(const Duration(milliseconds: 60), (timer) { valueController?.value += 0.5; }); } /// 进行动画 void stopAnimation() { timer?.cancel(); timer = null; } /// 重置动画 void resetAnimation() { stopAnimation(); valueController?.value = 0; }}总结像本例中的动画成果,如果用代码来编写,工夫老本会很大很大,如果靠图片的沉积,实现起来也很麻烦,而且因为图片的数量增多,安装包的体积也会减少很多。然而用rive,实现起来却很不便,可能惟一的老本就是设计师同学的学习老本。 ...

April 23, 2023 · 2 min · jiezi

关于flutter:flutter系列之如何自定义动画路由

简介flutter中有默认的Route组件,叫做MaterialPageRoute,个别状况下咱们在flutter中进行跳转的话,只须要向Navigator中传入一个MaterialPageRoute就能够了。 然而MaterialPageRoute太普通了,如果咱们想要做点不同的跳转特效应该如何解决呢? 一起来看看吧。 自定义跳转应用失常状况下,咱们进行路由跳转须要用到Navigator和MaterialPageRoute,如下所示: Navigator.push(context, MaterialPageRoute(builder: (context) { return const NextPage();如果要实现特定的路由动画,那么须要进行路由的自定义。 在flutter中也就是要应用PageRouteBuilder来自定义一个Route。 先来看下PageRouteBuilder的定义: class PageRouteBuilder<T> extends PageRoute<T> { PageRouteBuilder({ super.settings, required this.pageBuilder, this.transitionsBuilder = _defaultTransitionsBuilder, this.transitionDuration = const Duration(milliseconds: 300), this.reverseTransitionDuration = const Duration(milliseconds: 300), this.opaque = true, this.barrierDismissible = false, this.barrierColor, this.barrierLabel, this.maintainState = true, super.fullscreenDialog, })PageRouteBuilder也是PageRoute的一种,在构建PageRouteBuilder的时候,通过管制不同的属性值,咱们能够自在管制pageBuilder,transitionsBuilder,transitionDuration,reverseTransitionDuration等个性。 能够看到自在水平还是十分高的。 其中pageBuilder是路由将会跳转的页面,这个是必须要指定的,要不然路由也就没有意义了。 另外路由转换的成果能够经由transitionsBuilder来设置。 这里的RouteTransitionsBuilder是一个Function,返回一个Widget: typedef RouteTransitionsBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child);所以实践上,咱们能够返回任何widget,然而一般来说,咱们会返回一个AnimatedWidget,示意一个动画成果。 flutter动画根底flutter中有个专门的动画包叫做flutter/animation.dart, flutter中所有动画的外围叫做Animation。 Animation中定义了很多listener用来监控动画的变动状况,并且还提供了一个AnimationStatus来存储以后的动画状态: abstract class Animation<T> extends Listenable implements ValueListenable<T> { const Animation(); AnimationWithParentMixin<T> @override void addListener(VoidCallback listener); @override void removeListener(VoidCallback listener); void addStatusListener(AnimationStatusListener listener); void removeStatusListener(AnimationStatusListener listener); AnimationStatus get status;AnimationStatus是一个枚举类,它蕴含了当初动画的各种状态: ...

April 19, 2023 · 1 min · jiezi

关于flutter:都这样了我还是没法关闭微信朋友圈广告

前言不同微信版本,敞开广告的形式不一样,明天尝试敞开微信版本 8.0.33 广告,然而发现最初还是关不掉,故写下此文,心愿对大家死了敞开广告这条心! 操作如下步骤一:点击设置—>对于微信 步骤二:点击进入《隐衷爱护指引》 步骤三:在第一大类中找到 1.34 小类,其中有个蓝色字样《个性化广告》,点击进入。 步骤四:默认广告个性化是关上的,先不要敞开,如果默认敞开就先关上。这样能力保障广告趣味治理可显示可点击。 步骤五:点击上述步骤中的 ⑤ 进入个性化广告治理界面,点击 ⑥ 把每个标签都敞开。 步骤六:标签敞开后如图所示,点击实现按钮。 步骤七:如此退出到个性化广告治理界面,敞开 ⑧ 处按钮如图所示。 至此敞开了所有朋友圈广告。阐明广告波及到收益相干,任何非良心商家只会越藏越深,不保障非 8.0.33 当前版本是否无效,到时候再出新教程。一劳永逸的办法是:请继续关注wx: 编程黑板报。

April 18, 2023 · 1 min · jiezi

关于flutter:抢鲜解读Flutter-37更新啦

本文首发自「慕课网」,想理解更多IT干货内容,程序员圈内热闻,欢送关注"慕课网"! 作者:CrazeCodeBoy|慕课网讲师 新年伊始,由 Flutter 3.7 正式版来「打头阵」!咱们与整个 Flutter 社区们持续在 Flutter 3.7 中优化了框架,包含创立自定义菜单栏和层叠式菜单、更好的国际化工具反对、新的调试工具以及其余性能和个性等。 新的稳定版里,咱们在继续改良一些个性,例如全局文本抉择、Impeller 渲染速度、DevTools 以及始终以来都在优化的性能。让咱们一起来疾速摸索 Flutter 3.7 的新个性吧! 加强对 Material 3 的反对 在 Flutter 3.7 中,以下的 widget 曾经进行了 Material 3 的适配: BadgeBottomAppBarFilled and Filled Tonal buttonsSegmentedButtonCheckbox DividerMenusDropdownMenuDrawer and NavigationDrawer ProgressIndicatorRadio buttonsSliderSnackBarTabBarTextFields and InputDecoratorBanner你能够间接在利用中的 ThemeData 里设置 useMaterial3 来启用 Material 3。只有在残缺的色彩计划下能力展现出 Material 3 最残缺的细节,你能够应用新的 Material 主题构建器 生成你的主题配置,也能够通过 Flutter ThemeData 结构中的 colorSchemeSeed (色彩种子) 主动生成一整套的主题: 若想理解 Flutter 在 Material 3 上的反对进度,你能够在 GitHub 上查看 flutter #91605 号议题。 ...

April 11, 2023 · 4 min · jiezi

关于flutter:flutter系列之在flutter中使用相机拍摄照片

简介在app中应用相机必定是再平时不过的一项事件了,相机必定波及到了底层原生代码的调用,那么在flutter中如何疾速简略的应用上相机的性能呢? 一起来看看吧。 应用相机前的筹备工作flutter中为应用camera提供了一个叫做camera的插件,咱们首先须要装置这个插件。 装置插件的步骤很简略,如下所示: flutter pub add camera 该命令会在pubspec.xml中增加上面的内容: dependencies: flutter: sdk: flutter camera: ^0.10.0+1除了camera之外,咱们还须要对照相机拍摄的照片进行保留,这样咱们还须要用到path_provider和path这两个plugin。 咱们应用同样的形式对这两个插件进行装置。 装置好之后,咱们就能够在flutter中的代码中欢快的应用camera了。 在应用camera之前,咱们还须要获取相应的权限信息,比方在IOS中,咱们须要在 ios/Runner/Info.plist中增加上面的权限信息: <key>NSCameraUsageDescription</key><string>flutter须要用到你的照相机</string>在andorid中须要配合minSdkVersion>=21来应用。 在flutter中应用cameracamera插件为咱们提供了一系列的性能来不便camera的应用。 camera的应用须要遵循上面的步骤,因为当初的手机可能会有多个摄像头,所以咱们须要通过api获取到能够应用的摄像头列表。 接下来咱们应用选中的摄像头,进行一些管制操作,而后须要应用相应的camera视图来展现相应的照相机图像. 最初调用摄像头相干的拍摄性能进行拍摄。 听起来如同挺简单的,事实上只有遵循下面的程序,一切都是非常简单的。 首先咱们须要获取可用的摄像头列表,这个步骤是通过调用camera包中的availableCameras办法来实现的: Future<List<CameraDescription>> availableCameras() async { return CameraPlatform.instance.availableCameras();}availableCameras是一个异步办法,返回的是一个Future对象,其中的值是CameraDescription列表。 CameraDescription是对camera的形容文件: const CameraDescription({ required this.name, required this.lensDirection, required this.sensorOrientation, });name是摄像头的名称,lensDirection是摄像头面对的方向,sensorOrientation是传感器的方向,也就说你的手机是失常搁置,还是抉择90度搁置。 因为availableCameras是一个异步办法,所以咱们须要把它包裹在一个异步办法中进行调用: Future<void> main() async { // 保障所有的插件都加载结束 WidgetsFlutterBinding.ensureInitialized(); //获取摄像头列表 final cameras = await availableCameras(); //拿到第一个摄像头 final firstCamera = cameras.first; ....这里咱们拿到了第一个摄像头,留神,这里的firstCamera是一个CameraDescription对象。 因为模拟器上没有摄像头,如果你是在模拟器上运行下面的程序的话,将会抛出上面的异样: [VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: No element#0 List.first (dart:core-patch/growable_array.dart:343:5)为了对这个camra进行管制, 咱们须要创立一个CameraController对象: ...

April 4, 2023 · 1 min · jiezi

关于flutter:Flutter技术在哈啰两轮的升级之路

上一篇,咱们分享了Flutter在两轮的利用推广,本次分享的主题是Flutter在两轮的降级之路,次要分为两局部。一是咱们在Flutter落地之后,因为业务的倒退,导致咱们须要对Flutter进行降级。二是降级之后咱们遇到了一些问题,这里列举了一个比拟典型的案例——FlutterEngine的自定义。 背景介绍降级起因两轮从2019年来开始应用flutter,算是利用比拟早的团队。随后flutter降级了2.x版本,这个版本有个比拟重要的更新就是空平安(nullsafety),因为在1.x的版本,如果一个对象为null之后,再去调用它的任何办法,都会抛异样,在页面上的体现就是页面假死,也不会再刷新了。所以就须要研发人员关注下本人应用变量时是否曾经为空了,2.0会强加这个查看,在编译阶段让咱们确定好次变量是否可空以及是否懒加载,这样在咱们应用变量时,就会有零碎揭示咱们,相当于帮咱们做了这个工作,缩小出错率。其实很多其余语言也都有这样的检测机制。再加上一些性能的提优,于是有了降级的诉求。 Flutter版本敲定 这里比照了一下1.x版本和2.x版本的次要区别。2.x版本优化了利用启动的提早,调用Dart VM的GC策略也做了一些改良,低端Android设施的初始帧出线间隔时间最多缩小了约300ms。 此外,空对象音讯是咱们在开发中最常见的exception,所以空平安是很有必要的。pub.dev曾经公布了超过1000个空平安package,包含来自Dart、Flutter、Firebase和Material 团队公布的数百个package。 降级施行基础设施基础设施降级次要波及到两方面,打包机sdk降级和集体研发侧版本管理工具。因为SDK降级在2.8.1版本删除了一些被弃用的Api,会造成咱们编译报错。可参考以下批改: 切换本地环境为2.8.1版本运行工程查看报错批改对应报错库的api本地运行胜利后,挪动端CI/CD零碎发库提测测试同学全量回归,灰度降级节奏整体的降级节奏包含:根底降级启动、各个业务线研发启动、业务线null_safety革新1-n次、全量回归、灰度公布和异样观测。 本次2.0降级工作量根本都在null_safety语法革新上,因为工作量大波及范围广所以无奈在短期内实现语法革新。所以本次革新将按照业务性能划分,尽量收拢每次语法革新带来的影响范畴,从而引起测试侧屡次全量测试的人力节约。 Flutter空平安健全的空平安已在 Dart 2.12 和 Flutter 2.0 及更高版本中可用。Dart 3 及当前的版本将只反对健全的空平安。 有了空平安,上面代码中所有的变量都是非空的: 依赖项查看应用官网工具进行类型推断,最好确保依赖的所有包都曾经降级为null safe版本。所以在革新时应该从底层向上逐渐降级。 在控制台执行如下命令:dart pub outdated —mode=null-safety能够查看到以后我的项目工程依赖包是否是null safe。 对于其中不符合要求的外部库,须要手动降级后打包,生成null safe版本,倡议版本号比之前最新版减少一个大版本;对于三方库能够在三方库官方站点或者中文站点查找合乎null safe的最新版本号,并批改我的项目工程的yaml文件。 全副依赖批改实现后,执行命令拉取最新依赖: flutter pub getflutter pub upgrade操作实现之后能够应用第一步的命令查看是否依赖都校对完了。 如果提醒所有依赖都申明反对null safe,或者冀望跳过依赖查看,就能够进行后续操作。 执行胜利之后,会生成url,点击可在浏览器中应用迁徙工具: 左侧是须要迁徙的文件目录,官网工具会对选中文件进行类型推断并主动增加如下标记: ! (类型不可为空)? (类型可为空)late (初始化延时)late final (一次性初始化延时)required (参数标记)面板两头能够看到具体改变,右侧能够看到以后文件改变的起因。 对于不须要迁徙或者大型文件须要分步迁徙的场景,能够只勾选须要迁徙的文件目录,官网迁徙工具会主动为不须要迁徙的文件顶层增加null unsafe Dart的版本正文。 引入反对null safe的第三方库在更改本地代码时,个别都须要先降级依赖的第三方库,然而在官网第三方库下载地址https://pub.flutter-io.cn或者中文站点https://pub.flutter-io.cn中查问到依赖库的最新版本。 常见谬误及批改形式谬误1:The non-nullable variable 'preferences' must be initialized.起因:非空的动态变量或者顶层变量在申明时没有初始化,诊断器就会报此谬误。因为flutter对于没有初始化的变量会主动赋值为null,而该变量并没有申明可空。 解决办法: 谬误2:The method '*' can't be unconditionally invoked because the receiver can be 'null'.起因:可能为空的变量间接应用'.'调用办法,诊断器就会报此谬误。 ...

April 4, 2023 · 2 min · jiezi

关于flutter:Flutter-异步编程指南

作者:京东物流 王志明 1 Dart 中的事件循环模型在 App 开发中,常常会遇到解决异步工作的场景,如网络申请、读写文件等。Android、iOS 应用的是多线程,而在 Flutter 中为单线程事件循环,如下图所示 Dart 中有两个工作队列,别离为 microtask 队列和 event 队列,队列中的工作依照先进先出的程序执行,而 microtask 队列的执行优先级高于 event 队列。在 main 办法执行结束后,会启动事件循环,首先将 microtask 队列中的工作一一执行结束,再去执行 event 队列中的工作,每一个 event 队列中的工作在执行实现后,会再去优先执行 microtask 队列中的工作,如此重复,直到清空所有队列,这个过程就是 Dart 事件循环的解决机制。这种机制能够让咱们更简略的解决异步工作,不必放心锁的问题。咱们能够很容易的预测工作执行的程序,但无奈精确的预测到事件循环何时会解决到你冀望执行的工作。例如创立了一个延时工作,但排在后面的工作完结前是不会解决这个延时工作的,也就说这个工作的等待时间可能会大于指定的延迟时间。 Dart 中的办法一旦开始执行就不会被打断,而 event 队列中的事件还来自于用户输出、IO、定时器、绘制等,这意味着在两个队列中都不适宜执行计算量过大的工作,能力保障晦涩的 UI 绘制和用户事件的疾速响应。而且当一个工作的代码产生异样时,只会打断当前任务,后续工作不受影响,程序更不会退出。从上图还能够看出,将一个工作退出 microtask 队列,能够进步工作优先级,然而个别不倡议这么做,除非比拟紧急的工作并且计算量不大,因为 UI 绘制和解决用户事件是在 event 事件队列中的,滥用 microtask 队列可能会影响用户体验。 总结下 Dart 事件循环的次要概念: Dart 中有两个队列来执行工作:microtask 队列和 event 队列。事件循环在 main 办法执行结束后启动, microtask 队列中的工作会被优先解决。microtask 队列只解决来自 Dart 外部的工作,event 队列中有来自 Dart 外部的 Future、Timer、isolate message,还有来自零碎的用户输出、IO、UI 绘制等内部事件工作。Dart 中的办法执行不会被打断,因而两个队列中都不适宜用来执行计算量大的工作。一个工作中未被解决的异样只会打断当前任务,后续工作不受影响,程序更不会退出。1.1 向 microtask 队列中增加工作能够应用顶层办法 scheduleMicrotask 或者 Future.microtask 办法,如下所示: ...

April 4, 2023 · 5 min · jiezi

关于flutter:Flutter中如何取消任务

前言在开发过程中,勾销需要是很常见的,但很容易被疏忽。然而,勾销需要的益处也很大。例如,在页面中会发送很多申请。如果页面被切走并处于不可见状态,就须要勾销未实现的申请工作。如果未及时勾销,则可能会导致以下负面影响: 耗费用户额定数据流量。工作回调持有全局上下文变量,未及时开释存在内存透露危险异步申请过多耗费大量系统资源,拖慢 UI 线程,造成卡顿。在 Flutter 中,如何勾销曾经在进行的工作呢?首先须要把握一些基础知识。 前置常识Future#any 办法传入一个 Future 工作列表,返回第一个实现的异步工作,无论胜利或失败。 定义 用法如下 5 个异步工作,代码第五行尽管第二执行,然而最先执行结束,所以第一个返回,至此整个 Future.any 函数执行结束。 后果输出如下: 总结Future.any 理论就是一个 Completer,N 个 Future 叠加在一起,谁先实现算谁的。Future.any 能够了解成百米赛跑,其中每个选手就是一个 Future,谁跑最快到起点谁就赢了。Dio 勾销实现解析dio 版本dio: dev v5.0.3 git: 67f07b86a0976c14a6e19061563832d92ed6772b branch: main 如何勾销申请中传入 CancelToken 对象,而后调用 token.cancel 办法即可 final cancelToken = CancelToken();dio.get(url, cancelToken: cancelToken).catchError((DioError err) { if (CancelToken.isCancel(err)) { print('Request canceled: ${err.message}'); } else{ // handle error. }});// Cancel the requests with "cancelled" message.token.cancel('cancelled');流程解析思路:在理论工作执行前应用 Future.any 函数插入勾销工作。如果理论工作没有执行完,就有机会勾销它。 如下代码,黄色标注依照步骤来读就行。 ...

April 2, 2023 · 1 min · jiezi

关于flutter:OpenTranslator一款基于ChatGPT-API的翻译神器

这是一款应用 ChatGPT API 进行划词翻译和文本润色的浏览器插件。借助了 ChatGPT 弱小的翻译能力,它将帮忙您更流畅地浏览外语和编辑外语。 它无能啥一. 可翻译 二. 可润色 三. 可总结 四. 可剖析 五. 可解释程序代码 插件地址OpenAI Translator 劝退申明因为是基于 ChatGPT 的,所以必须先有个 ChatGPT 账号。注册参考ChatGPT 注册链接参考因为 ChatGPT 有反对国家,所以你必须先翻墙。翻墙能够买付费软件,自行查阅网络,不分明可留言或私信。装置具体过程一. 配置秘钥如果应用过程中呈现如下提醒,示意以后插件未配置秘钥。 二. 找到秘钥1. 跳转到秘钥查看页面(秘钥页)2. 点击 Create new secret key 按钮 3. 复制秘钥 4. 将上述秘钥复制到 OpanAI Translator 选项中 5. 在浏览器中选中任意文字呈现图标点击即可操作

March 30, 2023 · 1 min · jiezi

关于flutter:flutter系列之在flutter中使用媒体播放器

简介当初的app性能越来越弱小,除了根本的图文之外,还须要各种各样的其余的性能,比方视频,和直播。 直播可能会比较复杂,因为波及到了拉流和推流,须要服务器端的反对,然而视频播放就比较简单了,那么如何在flutter中应用媒体播放器呢? 一起来看看吧。 应用前的筹备工作flutter自身是不反对媒体播放性能的,为了实现这个性能,咱们须要应用额定的第三方插件叫做video_player。 首先咱们须要向flutter利用中增加video_player。增加起来也非常简单,只须要执行上面的命令即可: flutter pub add video_player 该命令会向pubspec.xml中增加如下的内容: dependencies: flutter: sdk: flutter video_player: ^2.4.7增加好依赖包之后,咱们还须要为利用增加相应的权限,你确保可能应用影音播放的权限。 如果是在android中,须要向AndroidManifest.xml文件中增加相似上面的内容: <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application ...> </application> <uses-permission android:name="android.permission.INTERNET"/></manifest>在IOS中则须要在Info.plist中增加上面的内容: <key>NSAppTransportSecurity</key><dict> <key>NSAllowsArbitraryLoads</key> <true/></dict>在flutter中应用video_playervideo_player中和video播放相干的类叫做VideoPlayerController,在IOS中底层应用的是AVPlayer,在Android中底层应用的是ExoPlayer。 VideoPlayerController有好几种构造方法,咱们一起来看看。 VideoPlayerController.assetasset办法示意video是从应用程序的asset中获取的。 VideoPlayerController.networknetwork办法示意video是从网络中获取的。 VideoPlayerController.filefile办法示意video是通过'file://${file.path}' 这样的格局来获取的。 还有一个只用在andorid中的办法,示意从contentUri中加载video: VideoPlayerController.contentUri为了简略起见,这里咱们抉择网易下面的一个科教视频,作为要播放的video。 那么咱们能够通过 VideoPlayerController.network办法来构建这个controller: videoPlayerController = VideoPlayerController.network( 'https://flv.bn.netease.com/1c04bfd72901f0661b486465e09cfdc01754c20db0686786f4e20a5f7d271ba0de6c1177a0da1c4c2d7c367e20ee16d4a90ac7ff4ea664820ba1b401f3e53f135f72cdff855e78ca5fb7849fb6ff7ccb9de1613ad3bfc59db83493b5f18a0a27f15048df6585361cd67c3b37551e10981c40dcdfdb77b7e6.mp4', );在应用video之前,还须要进行初始操作,初始化是调用它的initialize办法,这个办法的作用是关上给定的数据源,并加载它的元数据。 因为initialize办法是一个耗时的操作,所以这个办法返回类型是Future: Future<void> initialize() async {咱们能够这样应用: late Future<void> playerFuture;playerFuture = videoPlayerController.initialize();有了播放器的Future,咱们能够配合flutter中的FutureBuilder一起应用: body: FutureBuilder( future: playerFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return AspectRatio( aspectRatio: videoPlayerController.value.aspectRatio, child: VideoPlayer(videoPlayerController), ); } else { return const Center( child: CircularProgressIndicator(), ); } }, ),在FutureBuilder中,咱们通过判断connectionState来判断视频是否加载结束,如果没有加载结束,则应用CircularProgressIndicator示意正在加载中。 ...

March 28, 2023 · 1 min · jiezi

关于flutter:在-Flutter-多人视频通话中实现虚拟背景美颜与空间音效

前言在之前的「基于声网 Flutter SDK 实现多人视频通话」里,咱们通过 Flutter + 声网 SDK 完满实现了跨平台和多人视频通话的成果,那么本篇咱们将在之前例子的根底上进阶介绍一些罕用的特效性能,包含虚构背景、色调加强、空间音频、根底变声性能。 本篇次要带你理解 SDK 里几个实用的 API 实现,绝对简略。 01 虚构背景虚构背景是视频会议里最常见的特效之一,在声网 SDK 里能够通过enableVirtualBackground办法启动虚构背景反对。(点击这里查看虚构背景接口文档)。 首先,因为咱们是在 Flutter 里应用,所以咱们能够在 Flutter 里放一张assets/bg.jpg图片作为背景,这里有两个须要留神的点: assets/bg.jpg图片须要在pubspec.yaml文件下的assets增加援用 assets: - assets/bg.jpg须要在pubspec.yaml文件下增加path_provider: ^2.0.8和path: ^1.8.2依赖,因为咱们须要把图片保留在 App 本地门路下如下代码所示,首先咱们通过 Flutter 内的rootBundle读取到bg.jpg,而后将其转化为bytes, 之后调用getApplicationDocumentsDirectory获取门路,保留在的利用的/data"目录下,而后就能够把图片门路配置给enableVirtualBackground办法的source,从而加载虚构背景。 Future<void> _enableVirtualBackground() async { ByteData data = await rootBundle.load("assets/bg.jpg"); List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); Directory appDocDir = await getApplicationDocumentsDirectory(); String p = path.join(appDocDir.path, 'bg.jpg'); final file = File(p); if (!(await file.exists())) { await file.create(); await file.writeAsBytes(bytes); } await _engine.enableVirtualBackground( enabled: true, backgroundSource: VirtualBackgroundSource( backgroundSourceType: BackgroundSourceType.backgroundImg, source: p), segproperty: const SegmentationProperty(modelType: SegModelType.segModelAi)); setState(() {});}如下图所示是都开启虚构背景图片之后的运行成果,当然,这里还有两个须要留神的参数: ...

March 28, 2023 · 4 min · jiezi

关于flutter:flutter-实现渐变动画矩形边框

最近碰到一个需要须要实现一个矩形,矩形边框为渐变色,并且要求渐变色一直滚动向前,如下图所示 次要思路参考自这篇文章 另外还有来自 chatgpt 的答复,实现成果如上图所示成果 具体实现思路用 CustomPainter 实现一个突变矩形边框 void paint(Canvas canvas, Size size) { // 创立一个矩形区域 final rect = Rect.fromLTWH(0, 0, 96, 38); final paint = Paint() ..shader = LinearGradient( // 渐变色值 colors: const [Color.yellow, Colors.green], // 此处是实现动画的要害 => 动静传入角度来实现动画 transform: GradientRotation(animation * 2 * pi), // 创立一个线性突变着色器对象并将其利用于矩形形态的填充 ).createShader(rect) ..style = PaintingStyle.stroke // 边框宽度为 2 留神边框宽度是在矩形外边,所以这个矩形的宽高就变为 100*42 ..strokeWidth = 2; // 实现圆角矩形 final rRect = RRect.fromRectAndRadius(rect, const Radius.circular(8)); canvas.drawRRect(rRect, paint); // 另外也可实现直角矩形/圆形 // 画直角矩形 canvas.drawRect(rect, paint); // 画圆形 参数:圆心坐标, 半径 canvas.drawCircle(Offset(48, 20), 50, paint); }动画实现借助显式动画 AnimationController 和 AnimationBuilder,具体写法看下方残缺代码 ...

March 22, 2023 · 2 min · jiezi

关于flutter:ChatGPT-何许人也

有时候会想,如果chatGPT是人,它会是一个怎么的人呢?上面是我的揣测过程。 首先,她应该是女人会揣测而不会计算你问它: 3457 * 43216 = ,它答复 149261912 (这是错的。正确后果是 149397712)。 之所以后果的 2 是对的,仅仅因为它读了太多的文字材料当前,隐约感觉到 7 结尾的文字,乘号,6 结尾的文字,和 2 结尾的文字比拟「押韵」从语感上比拟像一首诗。 所以它就学会了这样的文字,而不是学会了计算。 理性而不感性有没有感觉,当本人跟老婆吵架时,你讲什么正确的情理都是徒劳,她不在乎对错而在于你有没有顾及她的感触。这印证《男人来自火星,女人来自金星》中说到的一个观点:男人和女人在思维了解上有实质的不同,男人重视感性,女人重视理性。 没错,chatGPT不善于感性计算,在背诵了一堆堆文字材料后,她感觉”顺口”就认为是对的答案,就是这么任性就是这么理性。 所以,ChatGPT必定是记忆力超强,天生对数字逻辑无所不通的女人。 其次,她有工作教训且善解人意预训练:减少工作教训举个栗子:家里请阿姨,来你家之前阿姨会承受家政公司的岗前培训,怎么拖地,怎么弄饭,包含怎么带小孩,这样保障了阿姨到雇主家可间接干活。 ChatGPT一开始就晓得主观既定的自然规律,比方苹果是水果而不是石头。起因是在被应用之前它通过了岗前培训,也就是GPT中的P(Pre-trained 预训练和微调),保障它能够间接上手就干,而不是磨磨唧唧等你教完它所有之后才会干活。 预训练是给ChatGPT提供根底技能,让其有工作教训,间接上手就干,节约使用者老本。 微调:让她善解人意举个栗子:还是下面那个阿姨。 上岗后,阿姨的技能和习惯可能跟雇主的不一样,比方雇主要减肥,做饭就不做三菜一汤了,全副变青菜,不要白米饭要西蓝花,OK , 三菜一汤是预训练的标配后果,全副青菜是依据雇主习惯进行的微调。微调让chatGPT更加合乎本人口味了。 再比方:如果你要问chatGPT 你公司年假多少?他必定答复不进去。 然而如果给他录入你公司考勤制度信息之后,它就晓得你公司年假多少了。这个过程就是微调。 微调是给模型提供使用者个性化信息,让其与使用者更加同频,给使用者感觉是,它知我,知己也! 再次,她是语言学家当你用不同语言时,她晓得用对应语言你。 当你感觉文字太长,她能够帮你变短。 当你想要她翻译成别的语言,她能够翻译成外语。 这其中归功于GPT中的T:Transformer转换器。该模块作用相似电源转换器: 220v进12v出 转换器模块工作流程:转换器根据预训练中的教训,将输出转换成向量示意,该向量中蕴含了上下文,输出含意等信息(相似二维码)。向量能够看做GPT可辨认的数据结构,当使用者提出不同需要时,转换器依据该向量变换生成新的输入。 如图中,输出通过Encoder编码成向量,向量依据用户需要Decoder成不同长度,语言的输入。 转换器实现将固定输出转换成各种不同输入的性能。 最初本文联合生存中的例子揣测 ChatGPT 是怎么的人。ChatGPT 中理论过程比这个简单得多,其过程可能不谨严,但旨在对 ChatGPT 中 G P T 含意进行通俗化解释,心愿各位大佬喜爱。 彩蛋 参考链接Transformers Models in Machine Learning: Self-Attention to the Rescue ChatGPT 中,G、P、T 别离是什么意思? ...

March 22, 2023 · 1 min · jiezi

关于flutter:flutter-自定义-Drawer-组件不依赖-Scaffold

背景:我所开发的利用是一个点餐的平板利用,有着大量从右边或左边关上 drawer 的场景,最终实现的成果如上图所示 默认的 drawer 组件flutter 默认的 drawer 是集成在 Scaffold 组件上的,简略代码示例如下: Scaffold( drawer: Widget, // 从右边弹起一个抽屉 endDrawer: Widget, // 从左边弹起一个抽屉);敞开该抽屉可应用 Navigator.pop(context); ,从此能够看出关上 Drawer 其实是关上了一个新的路由页面除了应用上述 Navigator 的形式敞开抽屉,还有上面两种办法参考自这里,这两种办法的原理都是通过获取 ScaffoldState 对象而后调用其外部的 open、close 办法进行操作,上面是代码演示 查找父级最近的 Scaffold 对应的 ScaffoldState 对象 ScaffoldState _state = context.findAncestorStateOfType<ScaffoldState>()!;// 关上抽屉菜单_state.openDrawer();// 或者间接应用 Scaffold.of(contenxt)在 Flutter 开发中便有了一个默认的约定:如果 StatefulWidget 的状态是心愿暴露出的,该当在 StatefulWidget 中提供一个`of` 静态方法来获取其 State 对象,开发者便可间接通过该办法来获取;如果 State不心愿裸露,则不提供`of`办法借助 GlobalKey 来获取 ScaffoldState 对象(我上面的自定义 drawer 就是借助这种形式),代码演示如下: // 定义一个globalKey, 因为GlobalKey要放弃全局唯一性,咱们应用动态变量存储static GlobalKey<ScaffoldState> _globalKey= GlobalKey();Scaffold( key: _globalKey , //设置key ... )// 而后就能够这样关上 drawer 了 _globalKey.currentState.openDrawer()下面的默认 drawer 应用形式介绍完了,很容易发现这种形式必须依赖 Scaffold,但通常一个路由页面只有一个 Scaffold 而且是在最外层,况且他只能接管一个 drawer (当然能够通过条件判断来展现多个 drawer),如果是页面中关上 drawer 的场景特地多的话,应用起来就会特地麻烦,所以我写了一个自定义的 drawer 组件 ...

March 19, 2023 · 3 min · jiezi

关于flutter:基于声网-Flutter-SDK-实现互动直播

互动直播是实现很多热门场景的根底,例如直播带货、秀场直播,还有相似抖音的直播 PK等。本文是由声网社区的开发者“小猿”撰写的Flutter基础教程系列中的第二篇,他将带着大家用一个小时,利用声网 Flutter SDK 实现视频直播、发评论、送礼物等根底性能。 开发一个跨平台的直播的性能须要多久?如果直播还须要反对各种互动成果呢? 我给出的答案是不到一个小时,在 Flutter + 声网 SDK 的加持下,你能够在一个小时之内就实现一个互动直播的雏形。 声网作为最早反对 Flutter 平台的 SDK 厂商之一, 其 RTC SDK 实现次要来自于封装好的 C/C++ 等 native 代码,而这些代码会被打包为对应平台的动态链接库,最初通过 Dart 的 FFI(ffigen) 进行封装调用,缩小了 Flutter 和原生平台交互时在 Channel 上的性能开销。开始之前接下来让咱们进入正题,既然抉择了 Flutter + 声网的实现路线,那么在开始之前必定有一些须要筹备的前置条件,首先是为了满足声网 RTC SDK 的应用条件,开发环境必须为: Flutter 2.0 或更高版本Dart 2.14.0 或更高版本从目前 Flutter 和 Dart 版本来看,下面这个要求并不算高,而后就是你须要注册一个声网开发者账号 ,从而获取后续配置所需的 App ID 和 Token 等配置参数。 可拜访这里注册声网账号:https://sso2.agora.io/cn/v4/signup/with-sms如果对于配置“门清”,能够疏忽跳过这部分间接看下一章节。创立我的项目首先能够在声网控制台的项目管理页面上点击创立我的项目,而后在弹出框选输出项目名称,之后抉择「互动直播」场景和「平安模式(APP ID + Token)」 即可实现我的项目创立。 依据法规,创立我的项目须要实名认证,这个必不可少,另外应用场景不用太过纠结,我的项目创立之后也是能够依据须要本人批改。获取App ID在我的项目列表点击创立好的我的项目配置,进入我的项目详情页面之后,会看到根本信息栏目有个 App ID 的字段,点击如下图所示图标,即可获取我的项目的 App ID。 App ID 也算是敏感信息之一,所以尽量妥善保留,防止泄密。获取 Token为进步我的项目的安全性,声网举荐了应用 Token 对退出频道的用户进行鉴权,在生产环境中,个别为保障平安,是须要用户通过本人的服务器去签发 Token,而如果是测试须要,能够在我的项目详情页面的「长期 token 生成器」获取长期 Token: ...

March 17, 2023 · 7 min · jiezi

关于flutter:一招教你-Notion-文章导出到公众号

Notion是一个功能强大的笔记应用程序,有许多长处,包含: 用户敌对的界面跨平台反对能够结构化组织笔记多人合作能够增加多种类型的媒体文件能够增加评论和工作这些长处使Notion成为一个宽泛应用的笔记应用程序,实用于集体和团队应用。 然而,对于重度Notion用户,想间接公布文章到公众号,会遇到如下问题:* 如果将其导出为 Markdown 格局,可能会蕴含一些本地图片。这些图片须要手动上传到公众号的图片库中。如果图片数量较少还好,但如果数量较多,则会破费很多工夫。公众号文章格局与 Notion 文章格局不统一。因而,须要将 Notion 文章复制到第三方网站,以转换为适宜公众号浏览的文章格局。总的来说:操作步骤繁琐、耗时多且操作不够不便。 原操作步骤 在 Notion 中编写文章后,能够将其导出为 Markdown 格局。在公布网站上编辑文本并上传图片。将带图片的 Markdown 复制到 Markdown Nice,生成公众号文章。将文章复制并粘贴到公众号上公布。解决办法在chrome商店搜寻插件Notion converter - 笔记转换工具 装置后启用。 原理:在线notion中自身蕴含了图片曾经在Notion服务器,链接可间接应用。converter自带能够将Notion格局调整成更适宜公众号展现格局。 如因网络等起因无奈获取插件,可关注公众号:编程黑板报,后盾回复 converter 获取。以后操作步骤在浏览器中查看已实现的Notion文章,您能够看到右侧有个箭头图标。 点击蓝色三角形小图标,而后抉择剪刀图标,即可复制排版好的内容至公众号。 总结绝对于之前步骤省略了导出,上传本地图和转换到公众号步骤,真正做到有件(插件)在手公布不愁。

March 16, 2023 · 1 min · jiezi

关于flutter:Flutter技术在哈啰两轮的应用推广

背景介绍Android利用采纳Java或Kotlin编写,iOS利用采纳Objective-C和Swift编写,但当咱们要去开发反对多端的利用,每一端都须要独立研发、测试,直到上线。为了解决多端独立开发的问题,跨端技术的计划备受青眼。 两轮跨端技术的尝试要追溯到2019年,过后整个互联网行业都在提效的大背景推动下开始各种跨端计划的尝试,而前身还是两轮助力车团队的两轮大前端也开始了跨端技术计划的摸索。过后可供选择的跨端计划有React Native计划、Weex计划,H5离线化计划以及过后较火的Flutter技术计划,而咱们的指标是心愿可能找到稳固、适宜咱们业务个性,并且能够持续进行深耕的技术计划进行调研和尝试。 思考和调研支流的跨端计划次要分为两种,一种是将JavaScriptCore引擎当作虚拟机的计划,代表的框架是React Native。另一种应用自渲染引擎的计划,代表框架是Flutter。 框架层+原生渲染计划 它的开发语言选择了js,应用的语法和React完全一致,不用于个别React利用,它须要借助原生的能力来进行渲染,组件最终都会被渲染为原生组件。尽管给用户带来比拟好的体验,但性能方面不会很高。 以Web为根底的H5 Hybrid离线化计划 相对来说这是开发成本最小的一种计划,因为它实际上是在写前端的界面,和一般开发H5网页并没有太大的区别。这一计划所面临的次要考验就是性能问题以及因为网络提早而带来的用户体验问题。在此基础上咱们引入了离线化的计划,咱们打算是通过CRM平台发放H5离线包达到本地,应用WebView进行本地资源加载,来突破性能问题。 框架层+自渲染引擎计划 这种计划和下面的区别就是,它并没有间接借用原生能力去渲染组件,而是利用了更底层的渲染能力,本人去渲染组件。这种形式显然链路会比拟短,性能方面也会更突出,同时在放弃多端渲染一致性下面,也会比后面两种计划更加牢靠,这类框架的典型例子就是Flutter。 计划比照与抉择 咱们在抉择跨端计划的时候,不只是要思考常见的几种重要指标,如编程语言、性能、技术架构等来判断是否适宜咱们团队和产品,更多还要去思考开发效率、社区反对等工程化方面的指标,同时还要思考团队现状、所选计划的生态和技术将来的倒退方向。 比照计划制订在社区、成熟度趋于统一的时候,跨平台计划的性能就成了重要的思考因素和指标。性能更佳的Flutter当然是首选。另一方面,对于本来是Native开发的人来说,React Native与Flutter开发成本是相差不大的,从久远角度来看,抉择Flutter技术计划仿佛是较为适合的抉择。 同时联合过后组内的状况,咱们抉择了H5 Hybrid离线化和Flutter作为比拟计划进行端测的尝试。H5 Hybrid离线化计划相对来说比较简单,而且自主性比拟强,计划逻辑简略危险较小。如果试验胜利咱们能够走出一条自主翻新的跨端路线,而Flutter技术计划性能较高,社区也比拟沉闷,UI渲染框架做的较为彻底,也是过后跨端技术计划的代表方向。所以咱们综合以上的思考,心愿通过实际拿到要害的比照数据,为后续最终的计划抉择提供反对。 Flutter是什么Flutter是Google的挪动UI框架,能够疾速在iOS和Android上构建高质量的原生用户界面,它是Google一个新的用于构建跨平台的手机App的SDK。写一份代码,能够多端运行,Flutter同时能够与现有的代码一起工作,被越来越多的开发者和组织应用,并且Flutter是完全免费和开源的。 从官网的介绍来看,Flutter的特点能够总结成三点。一是跨平台,当初Flutter 3根本能够实现跨6种平台,甚至反对嵌入式开发。到目前为止Flutter算是反对平台最多的框架了,良好的跨平台性,间接带来的益处就是缩小开发成本。二是原生用户页面,让咱们的体验更好,性能方面也会更好。用官网的话就是平滑而天然的滑动成果和平台感知,为用户带来全新的体验。三是开源收费,同Android零碎一样,这些都是收费开源的。 计划线上验证通过一段时间的调研和剖析当前,咱们基本上确定了两轮跨端计划的技术选型和比照计划。本着审慎的准则,咱们破费了肯定的精力在这两个计划的验证比照、以及跨端技术计划的推动办法摸索上。 H5 Hybrid离线化计划针对该计划,咱们的打算是分两期执行。第一期是实现框架的外围代码,并在BOS端实现一个页面的革新上线,拿到线上运行数据。第二期是在第一期数据的根底上打造CRM平台,欠缺计划的零碎利用。 该计划的根本构造分为代码层、协定层、Hybrid离线SDK层以及离线包管理系统。其中的代码层是合乎特定规范的H5工程开发产生的代码。当H5页面产生资源或款式的申请时,容器层会检测资源申请事件,并依据资源协定寻找本地资源包对应地位的资源并进行加载。本地资源加载实现后,造成数据流申请响应返回H5页面。 数据的流转在框架中经验了数据散发、协定解析、指标执行、后果反馈几个阶段。通过在端侧建设协定层的封装,保障了协定规定对立。整个协定过程做了SDK化的封装,保障了外围框架层的稳固。 Flutter计划针对Flutter计划的尝试,咱们须要在一开始优先解决工程构造、打包构建、上线集成和原生工程混合开发的问题。 针对于工程构造,Flutter在业务上的利用须要一个Host载体,咱们抉择了Flutter Module工程作为Flutter业务工程的Host工程。向上输入构建产物对原生工程的继承,向下组装和汇合业务工程,造成对立的模块注入、页面注册的模式。 针对Flutter我的项目打包构建、上线集成和混合开发的问题,咱们须要联合过后公司产物构建和治理规定进行Flutter产物的构建。咱们的计划是在Jinkens下面创立独自的Job进行Flutter module产物的构建,最终把生成的Android和iOS产物集成到原生工程中,实现Flutter环境和代码的集成。以上便初步搭建实现了Flutter业务开发工程构造,并实现了在原生工程中混合开发、构建上线的一系列流程。 比对试验 在页面上线后,咱们很快拿到了一手数据。在稳定性方面两种计划体现都比拟好,没有呈现页面crash的状况。在加载性能、白屏或者异样方面,Flutter计划要比H5 Hybrid离线化计划体现得更好。综合以上运行状况比照,咱们根本确定了Flutter作为次要的大前端实际计划。 Flutter利用推动框架1.0阶段咱们对Flutter技术工程化利用生产了各种轮子,以求达到对Flutter标准、高效利用的目标,比方数据的流转散发、网络模块的封装、MVVM构造的组织等。这一阶段的框架次要分为页面路由治理、数据总线、工程框架、网络申请、资源管理和组件治理。总体来说在这一阶段,咱们对于Flutter利用根本造成了初具雏形的工程构造体系和根底能力建设。 框架2.0阶段在这一阶段Flutter的利用算是进入了深水区,随着利用场景的减少,各种问题裸露进去,其中比拟辣手的问题有Flutter状态治理、页面生命周期和混合插件缺失问题。针对Flutter状态治理、页面生命周期的问题,咱们基于原生开发的教训,搭建了一套合乎 MVVM规范的Flutter代码根底构造。 这套根底构造次要分为Page与VM两局部,组织关系如图所示。Page与VM逻辑离开,Page是对VM的封装,VM是业务逻辑的独立单元,蕴含了残缺的UI以及逻辑层Module。 上面是Page根底构造性能定义阐明。在这一构造中,咱们是以PageRoute为根底进行扩大封装。PageLifecycle定义了生命周期和生命周期状态值;LifecycleEventNotify负责生命周期事件的传递;LifecycleNotifyManager是生命周期框架的外围枢纽,所有的事件汇总到这里向下调用生命周期API;LifecycleFromFlutter和LifecycleFromBoost收集flutter原生和flutter boost的生命周期的调用,总结调整后依照新的生命周期标准发送事件;PageAnimation是页面动画的集成工具;WidgetProviderRender是页面UI搭建的工具类,负责provider、widget的创立和组装,最终造成残缺的页面;ModuleBinder是页面对Module的绑定工具,实现了module宿主的绑定,当宿主销毁时module能感知到并做出相应的反馈。 上面是VM层根底构造。VM层和Page层根本相似,不同的是它会依据VM的特点进行本身生命周期的感知和解决,解决形式绝对Page会更加简单。 Flutter Map组件针对以地图为代表的原生混合组件能力的建设,过后flutter社区的能力反对有余,没有适合的轮子应用,然而咱们的业务场景又是比拟重地图的。在这种状况下,咱们就须要本人去开发一套地图组件。 如图是Flutter Map的总体结构图,咱们利用的是flutter框架的PlatformView机制,在原生层实现view的实例化创立,再交给flutter进行UI的渲染,实现了原生view在flutter体系中的渲染和展现。接下来咱们须要在flutter层与原生view进行操控,这里须要咱们可能精确找到对应的原生view,并通过channel通道传播相干的指令。原生view收到指令当前,会依据规定做出相应的动作,并产生后果原路返回给调用方。原生view产生一些事件状态时,比方地图的拖动、加载实现等事件,须要及时传递给flutter端,同时flutter端有一些状态也须要传递给原生端,以便业务侧和原生view侧都可能及时做出相应的反馈。这里咱们以channel为根底建设了双工通道,实现了flutter与 platform两端实现实时进行事件告诉的能力。 Flutter规范体系化建设阶段 在这一阶段咱们的flutter在两轮大量的业务场景的利用实际下,根本趋于稳定的状态,通过咱们在这一阶段对flutter的体系化革新,造成了汇合flutter工程搭建、开发调试、根底能力积淀以及开发规范输入的体系化构造。 Git仓库整顿在仓库构造方面,咱们整合了散乱的flutter仓库保护状态,造成了当初对立、规范、聚合的仓库汇合。目前的仓库叫HBFlutter,包含中间件子分组、根底组件子分组、native能力子分组和其余子分组。 组件分类在根底能力积淀方面,咱们对现有根底组件进行了梳理和标准化革新,根本造成了一套体系化的flutter根底能力建设。 技术总结Flutter技术目前在两轮失去了利用和推广,在哈啰App两轮业务场景下根本实现了全量Flutter化革新,Bos App也在往年开启了Flutter技术改造,目前曾经根本实现大部分流程的Flutter化革新,目前线上运行绝对安稳。两轮业务在利用Flutter技术后实现了开发效率的大幅度晋升,同时也很大水平上解决了Android和iOS UI不统一的问题。后续咱们将持续追踪Flutter技术的倒退,并视业务场景的需要进行正当的利用和推广。 (本文作者:田克雨)

March 15, 2023 · 1 min · jiezi

关于flutter:flutter系列之创建一个内嵌的navigation

简介咱们在flutter中能够应用Navigator.push或者Navigator.pushNamed办法来向Navigator中增加不同的页面,从而达到页面调整的目标。 个别状况下这样曾经足够了,然而有时候咱们有多个Navigator的状况下,下面的应用形式就不够用了。比方咱们有一个主页面app的Navigator,而后外面有一个匹配好友的性能,这个性能有多个页面,因为匹配好友性能的多个页面实际上是一个残缺的流程,所以这些页面须要被放在一个子Navigator中,并和主Navigator辨别开。 那么应该如何解决呢? 搭建主Navigator主Navigator是咱们app的一些次要界面,这里咱们有三个界面,别离是主home界面,一个setting配置界面和好友匹配界面。 其中好友匹配界面蕴含了三个子界面,这三个子界面将会用到子路由。 先来看下主路由,主路由的状况跟一般的路由没啥区别,这里咱们首先定义和home和setting匹配的两个widget:HomePage和SettingsPage: class HomePage extends StatelessWidget { const HomePage({ super.key, }); @override Widget build(BuildContext context) { return Scaffold( appBar: _buildAppBar(context), body: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( mainAxisSize: MainAxisSize.min, children: const [ SizedBox( width: 250, height: 250, child: Center( child: Icon( Icons.home, size: 175, color: Colors.blue, ), ), ), SizedBox(height: 32), Text( '跳转到好友匹配页面', textAlign: TextAlign.center, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), ), ], ), ), ), floatingActionButton: FloatingActionButton( onPressed: () { Navigator.of(context).pushNamed(routeFriendMatch); }, child: const Icon(Icons.add), ), ); }HomePage很简略,它蕴含了一个floatingActionButton,当点击它的时候会调用 Navigator.pushNamed办法进行路由切换。 ...

March 13, 2023 · 2 min · jiezi

关于flutter:windows微信如何双开

生存中存在同时应用两个微信的状况,一个工作一个生存,这时心愿同时在电脑上登录两个账号。如何做到呢?步骤如下: 右键单击“微信”图标,抉择属性,指标框内的门路就是微信装置门路,复制指标框里的内容。 将如下命令复制到 TXT 文件保留,再将该文件重命名,次要是将后缀名改成“.bat”文件。 @echo offstart "" "C:\Program Files (x86)\Tencent\WeChat\WeChat.exe"start "" "C:\Program Files (x86)\Tencent\WeChat\WeChat.exe"exit✍ 留神: start 前面有一个空格,双引号前面也有一个空格,这两个个空格不能省,否则双开启动不了。C:\Program Files (x86)\Tencent\WeChat\WeChat.exe 为微信装置门路。肯定要保障后缀批改成 bat 胜利了,txt 批改后缀名操作请自行查阅网络。最终效果图: 双击“微信双开.bat”,会呈现两个微信登陆界面。 提醒:如果您想 3 开或多开微信,能够将这行代码 start "" "C:\Program Files (x86)\Tencent\WeChat\WeChat.exe"复制 3 行或多行。 当您须要 Win10 微信双开或 Win11 微信双开时,您只需双击微信双开.bat即可实现。 太棒了!激励本人坚持到底。我心愿我为你投入的工夫减少了一些价值。 如果感觉文章对你有帮忙,点赞、珍藏、关注、评论,一键四连反对,你的反对就是我创作最大的能源。 ❤️本文由公众号编程黑板报 原创,关注我,获取我的最新文章~❤️

March 9, 2023 · 1 min · jiezi

关于flutter:基于声网-Flutter-SDK-实现多人视频通话

前言本文是由声网社区的开发者“小猿”撰写的Flutter基础教程系列中的第一篇。本文除了讲述实现多人视频通话的过程,还有一些 Flutter 开发方面的知识点。该系列将基于声网 Fluttter SDK 实现视频通话、互动直播,并尝试虚构背景等更多功能的实现。 如果你有一个实现 “多人视频通话” 的场景需要,你会抉择从零实现还是接第三方 SDK?如果在这个场景上你还须要反对跨平台,你会抉择怎么样的技术路线? 我的答案是:Flutter + 声网 SDK,这个组合能够完满解决跨平台和多人视频通话的所有痛点,因为: Flutter 人造反对手机端和 PC 端的跨平台能力,并领有不错的性能体现声网的 Flutter RTC SDK 同样反对 Android、iOS、MacOS 和 Windows 等平台,同时也是难得针对 Flutter 进行了全平台反对和优化的音视频 SDK在开始之前,有必要提前简略介绍一下声网的 RTC SDK 相干实现,这也是我抉择声网的起因。 声网属于是国内最早一批做 Flutter SDK 全平台反对的厂家,声网的 Flutter SDK 之所以能在 Flutter 上最早放弃多平台的反对,起因在于声网并不是应用惯例的 Flutter Channel 去实现平台音视频能力: 声网的 RTC SDK 的逻辑实现都来自于封装好的 C/C++ 等 native 代码,而这些代码会被打包为对应平台的动态链接库,例如.dll、.so 、.dylib ,最初通过 Dart 的 FFI(ffigen) 进行封装调用。这样做的益处在于: Dart 能够和 native SDK 间接通信,缩小了 Flutter 和原生平台交互时在 Channel 上的性能开销;C/C++ 相干实现在取得更好性能反对的同时,也不须要适度依赖原生平台的 API ,能够失去更灵便和平安的 API 反对。如果说这样做有什么害处,那大略就是 SDK 的底层开发和保护老本会剧增,不过从用户角度来看,这无异是一个绝佳的抉择。 ...

March 7, 2023 · 6 min · jiezi

关于flutter:flutter系列之在flutter中自定义themes

简介个别状况下咱们在flutter中搭建的app基本上都是用的是MaterialApp这种设计模式,MaterialApp中为咱们接下来应用的按钮,菜单等提供了对立的款式,那么这种款式能不能进行批改或者自定义呢? 答案是必定的,一起来看看吧。 MaterialApp中的themesMaterialApp也是一种StatefulWidget,在MaterialApp中跟theme相干的属性有这样几个: final ThemeData? theme; final ThemeData? darkTheme; final ThemeData? highContrastTheme; final ThemeData? highContrastDarkTheme; final ThemeMode? themeMode;先来看下ThemeMode的定义: enum ThemeMode { system, light, dark,}ThemeMode是一个枚举类,外面有三个枚举值,别离是system,light和dark。 咱们都晓得当初手机有一个暗黑模式,ThemeMode的这三种模式就是为了适应暗黑模式而生的。 system示意是零碎默认的模式,light是亮堂模式,dark是暗黑模式。 而ThemeData则定义了主题中各种组件或者口头的配色。 那么如果咱们想要实现自定义themes的性能,就能够利用这个ThemeData类来重写其中要重写的色彩。 ThemeData中还有专门为color变动定义的ColorScheme,还有为Text变动设置的TextTheme,这两个theme实际上是一系列的color汇合。 除了ThemeData,flutter中还有一个类叫做Theme。 Theme是一个StatelessWidget,这个widget中蕴含了ThemeData,它提供了一个Theme.of办法来让子widget取得最近的ThemeData数据。 这就意味着,在flutter中,子widget能够应用和父widget不同的主题,十分的棒。 自定义themes的应用那么如何应用自定义themes呢?有两种形式。 第一种就是在应用MaterialApp的时候传入自定义的themes,如下所示: Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); }}然而这种操作理论是传入了一个全新的ThemeData,如果咱们只想批改局部ThemeData中的数据应该如何解决呢? 咱们能够应用Theme.of办法从以后的Theme中拷贝一份,而后再调用copyWith办法,传入要批改的自定义属性即可。 如下所示: Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: Theme.of(context).copyWith(useMaterial3: true), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); }}后面咱们提到了Theme这个widget,咱们还能够将要自定义Theme的widget用Theme包裹起来,实践上咱们能够将任何widget都用Theme来进行包装。 ...

March 6, 2023 · 1 min · jiezi

关于flutter:Flutter-下载篇-叁-网络库切换实践与思考

前言本文是对于应用flutter_download_manager下载性能的实际和摸索。咱们将基于flutter_download_manager的性能扩大,革新成本人想要的样子。在浏览本文之前,倡议先理解前两篇文章: Flutter 下载篇 - 壹 | flutter_download_manager源码解析Flutter 下载篇 - 贰 | 当下载器遇上网络库切换本文将基于第二篇中的扩大框架,将网络库从dio切换为httpclient,并联合革新过程中发现的问题提出本人的想法。 优化点:dynamic的告警问题 在第2和20行中,黄色标记表明,如果第2行中的每个网络库下载的返回值可能不同,则思考将其设置为“dynamic”,这可能导致第20行中呈现响应状态码的告警,因为该属性可能不存在。 为了确保 download 接口的返回值具备 statusCode 属性,在这里定义了一个专门的返回类以进行限度。具体定义如下: 这样就解决了statusCode告警问题,其中extra能够寄存原始download response对象。 HttpClient实现网络库只用实现上一篇中的网络接口CustomHttpClient,而后批改IDownloader:createObject其中网络注入对象即可,如下: //实现这个接口定义abstract class CustomHttpClient { Future<DownloadHttpResponse> download( String urlPath, String savePath, { DownloadProgressCallback? onReceiveProgress, DownloadCancelToken? cancelToken, Map<String, dynamic>? options, }); DownloadCancelToken generateToken();}------【idownloader.dart】----------abstract class IDownloader { factory IDownloader() => createObject( //将这个注入批改成咱们实现的即可 原来:customHttpClient: CustomDioImpl(), customHttpClient: CustomHttpClientImp(), );}实现代码: 第9-17行:次要是将flutter_download_manager中已下载但未下载残缺的文件大小传递给后端,以便告知后端从哪里持续下载文件。如果不传,会节约带宽和工夫。在解决大文件时,内存压力会增大,中断的可能性也会减少。此外,用户界面可能会呈现进度条跳跃的问题。第27-45行:将下载流写入传入的 savepath 文件中。须要留神 cancelToken.isCancelled 办法,因为上一篇中没有定义 isCancelled 属性,这里必须在 DownloadCancelToken 中提供该办法(第69行)。第55-65行:这里实现了HttpClientCancelToken的cancel办法,具体实现就是给标记位_isCancelled赋值。遇到官网问题实现上述实际后,发现官网进度谬误BUG。如果屡次暂停、勾销,而后再复原下载,会呈现进度起始地位谬误的问题。下载会从已下载文件的长度开始,成果如下所示: <p align=center><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7cf94ec2b45348b3b0ceee9aeeacdc0d~tplv-k3u1fbpfcp-watermark.image?" alt="221539959-e5af41bc-b3b1-41cc-9a46-1ba549c4fd86.gif" width="40%" /></p> ...

March 4, 2023 · 1 min · jiezi

关于flutter:Flutter-下载篇-贰-当下载器遇上切换网络库

需要背景继上篇《Flutter 下载篇 - 壹 | flutter_download_manager 源码解析》中具体介绍了 flutter_download_manager 用法和原理。在优缺点中提到,该库纯 Dart 实现,反对下载治理,暂停,复原,勾销和断点续传。其中有个毛病是网络库与 dio 强耦合,不反对自定义网络库扩大。 有人会说: dio 这么牛逼,间接用不就好了,为啥还要反对别的网络库,没事别瞎折腾。 我想说: 世界不只有一种声音,那不然多无趣。第三方库对利用自身来说是黑盒,开发者个别疏于关注其性能改变对利用影响除非产生重大事故,这种不可控的状况应审慎。设计上遵循 DIP 准则,形象不要依赖具体实现细节,具体细节依赖形象,咱们须要形象网络层来给我的项目依赖而非间接依赖 dio。疾速切换到其余网路库。本文将从现状登程,一步步带你解耦 flutter_download_manager 中的网络库。 现状阐明从类图上整体理解 flutter_download_manager 类设计过程中对 dio 强耦合概括,而后通过代码具体解说。 类图体现 代码体现耦合点一:dio.CancelToken 每个下载工作申请中都会应用到 dio:CancelToken 通过 dio 网络库间接实现工作的勾销性能。 耦合点二:dio.downloadcancelToken.cancel() 算依赖 CancelToken 如上简写代码中调用链关系,最终调用链及对 dio 依赖关系总结: 下载库对 dio 的依赖在于: CancelToken 和 download 办法。 如何定制网络库通过上述对现状剖析总结,联合设计根本准则:封装变动将不变从变动中隔离进去。其中变动的就是网络库的下载,CancelToken 和勾销性能。只用封装这部分变动,将网络库下载和 Token 形象进去进行封装。 1. 网络层设计目标:让 flutter_download_manager 与 dio.download 解耦。 思路:将网络相干操作形象成接口,依赖注入到 downloadManager 对象中。 施行步骤: 形象网络层接口思考到 download 返回 Future 中对象问题,因为会用到 response.statusCode,这里间接用 dynamic 来,具体能够细化成封装成 DownloadResponse,其中蕴含 statusCode 属性。 ...

March 3, 2023 · 1 min · jiezi

关于flutter:剖析flutterdownloadmanager学习如何做下载管理暂停和取消

前言内容类利用中图片或文件下载,个别利用中利用更新和降级,这些都是经典的下载场景。下载是我的项目中根底且重要的模块。 从代码逻辑复用性和人力老本思考,始终想实现一个纯Dart实现的下载库,作为技术储备。 最近发现了一个纯Dart实现的下载库flutter_download_manager,相对来说各方面还算满足需要,反对断点续传,暂停,勾销等我比拟看重的性能。然而有些中央还须要改良。 话不多说,首先简略介绍下这个库吧。 flutter_download_manager简介地址: https://github.com/nabil6391/flutter_download_manager 版本: 0.5.4 特点: 纯Dart实现通过 url 治理下载工作可能告诉状态和进度更改局部下载性能队列下载暂停、勾销或复原下载并行文件下载(2 个或能够更改)反对批量下载反对平台: Linux | MacOS | Windows | Android | iOS 应用办法简略下载一个文件var dl = DownloadManager();var url = "adasdad.com/asda.sdas";dl.addDownload(url, "./test.sdas");DownloadTask? task = dl.getDownload(url4);task?.status.addListener(() { print(task.status.value);});task?.progress.addListener(() { print(task.progress.value);});await dl.whenDownloadComplete(url4);获取下载状态DownloadTask? task = dl.getDownload(url4);task?.status.addListener(() { print(task.status.value);});获取下载进度DownloadTask? task = dl.getDownload(url4);task?.progress.addListener(() { print(task.progress.value);});期待工作实现DownloadTask? task = dl.getDownload(url4);await task.whenDownloadComplete();勾销下载工作var dl = DownloadManager();dl.cancelDownload(url5);暂停下载工作var dl = DownloadManager();dl.pauseDownload(url5);复原下载工作var dl = DownloadManager();dl.resumeDownload(url5);成果展现 源码解析类图 工作治理类:DownloadManager整个外围就类DownloadManager, 而每个下载工作的形象是DownloadTask,所谓Manager当然是要治理这些Task了。那么如何治理呢? 游离的没法管控,只有先找到能力调配,通过Map持有Task句柄达到“找到”目标,其中_cache中以<下载URL,下载工作>形式在内存中缓存每个工作状态;而_queue则是新增加的下载工作申请,这两者关系前面流程中会具体讲到。 工作的形象:DownloadTask重点说下status和progress字段设计,不论是批量下载还是单任务下载,进度监听不是通过传统传入一个回调给download或者addDownload来进行的,而是用了零碎的ValueNotifier。笔者思考这样设计起因是配合flutter零碎提供的ValueListenerBuilder更容易组织UI。(这样的设计是不是看起来更Dart) 工作申请形象:DownloadRequest重点说下cancelToken,该字段在暂停,勾销,复原下载工作实现中起了关键作用。像放出去的风筝,想发出时能够发出。怎么发出呢?通过线,这条线的作用就是cancelToken。而风筝就像是一个个工作申请,放风筝的人就是Manager,放风筝这件事就是Task。 每个申请都必须带个cancelToken,不便勾销申请。(不带线的风筝,难道让你入地?) 未标明办法阐明图中DownloadManager中办法只写了单任务下载相干办法,批量相干办法差不多就省略了,相似(add | pause | cancel | resume | remove ).BatchDownload等,最终通过循环执行了单实现的办法。 ...

March 3, 2023 · 1 min · jiezi

关于flutter:参与-2023-第一季度官方-Flutter-开发者调查

Flutter 3.7 曾经正式公布,每个季度一次的 Flutter 开发者考察也如约而至,邀请社区的各位成员们填写! 调查表链接: https://flutter.cn/urls/2023q1wx 本次调研将会波及既有的对 Flutter 整体和子系统的满意度,以及在 更新 Flutter SDK 时的体验 和 遇到破坏性改变 (Breaking changes) 时的反馈,也有 针对 Flutter 近期风行度的考察 和 深层链接的应用 的相干问题。本调查表在大屏幕的设施上 (如笔记本电脑或台式电脑) 的体验更佳。你能够随时来到问卷页面,并在不便的时候返回持续填写,但请留神 本次调研将于 3 月 10 日截止。 再次感激每一位参加社区调研的开发者们!

March 2, 2023 · 1 min · jiezi

关于flutter:Flutter-dio如何设置网络代理

dio版本是4.0.6设置方法 import 'package:dio/adapter.dart';import 'package:dio/dio.dart';Dio dio = Dio();//网络代理设置方法(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) => true; client.findProxy = (uri) { // 代理,这里localhost:888须要依据理论状况设置相应代理地址 String proxy = 'PROXY localhost:8888'; debugPrint('flutter_proxy $proxy'); return proxy; }; };dio版本5.0.1设置方法 import 'package:dio/io.dart';void initAdapter() { dio.httpClientAdapter = IOHttpClientAdapter()..onHttpClientCreate = (client) { // Config the client. client.findProxy = (uri) { // Forward all request to proxy "localhost:8888". return 'PROXY localhost:8888'; }; // You can also create a new HttpClient for Dio instead of returning, // but a client must being returned here. return client; };}

March 1, 2023 · 1 min · jiezi

关于flutter:flutter系列之Navigator的高级用法

简介上篇文章咱们讲到了flutter中navigator的根本用法,咱们能够应用它的push和pop办法来进行Router之间的跳转。 在flutter中一个Router就是一个widget,然而在Android中,一个Router就是Activity,在IOS中,一个Router是一个ViewController。 Router除了之前讲过的push和pop办法之外,还有一些更加高级的用法,一起来看看吧。 named routes尽管在flutter中navigator将routers以stack的模式进行存储,能做的也只是push和pop操作,然而事实上Router是能够有名字的。 想想也是,如果Router没有名字的话,那么如何顺利进行跳转呢?不可能每次都new一个Router进去吧。 navigator有一个办法叫做Navigator.pushNamed()用来将带名字的Router压入堆栈,咱们来看下它的定义: static Future<T?> pushNamed<T extends Object?>( BuildContext context, String routeName, { Object? arguments, }) { return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments); }这个办法须要传入一个context和对应的routeName,同时还能够带一些参数。 那么怎么用这个办法呢? 首先咱们须要定义一些Router,比如说在创立MaterialApp的时候能够传入routes参数,来设置named Routers: MaterialApp( title: '这是named Routers', initialRoute: '/firstPage', routes: { '/firstPage': (context) => const FirstPage(), '/secondPage': (context) => const SecondPage(), },)下面的代码中咱们别离定了两个routers,别离是firstPage和secondPage,他们别离对应一个自定义的widget。 定义好Router之后,咱们就能够向上面这样应用了: onPressed: () { Navigator.pushNamed(context, '/secondPage');}如果要返回第一个页面的话,那么能够调用Navigator.pop办法来实现: onPressed: () { Navigator.pop(context);}给named route传参数在上一节咱们讲到pushNamed的时候,还介绍了它还能够接管参数arguments。从定义上能够看到arguments的类型是Object对象,也就是说任何对象都能够作为named route的参数。 那么咱们先定义一个对象如下: class TestArguments { final String name; final String description; TestArguments(this.name, this.description);}接下来咱们须要创立一个可能承受这个参数的Routers。 ...

February 27, 2023 · 2 min · jiezi

关于flutter:与-Flutter-共创未来-Flutter-Forward-活动精彩回顾

作者 / Google 开发者框架和语言 (含 Flutter、Dart 和 Go) 产品经理 & 用户体验总监 Tim Sneath 咱们很快乐能够在 Flutter Forward 流动 上分享咱们对 Flutter 的愿景。Flutter Forward 是在肯尼亚内罗毕以线上直播形式举办的开发者流动,世界各地的开发者可能亲自参加或者近程相聚,摸索 Flutter 的将来倒退方向。 Flutter 是一个界面工具包,它让利用开发者只需编写一套代码,即可构建挪动利用、Web 利用和桌面利用。您能够应用 Flutter 构建粗劣好看的利用,屏幕上的每一个像素尽在把握。Flutter 具备如下独特劣势: 疾速 。反对硬件加速图形和原生编译的机器代码,可充分发挥手机或电脑硬件的计算能力。高效 。反对有状态热重载等技术,让您可立刻看到代码更改在利用中的实际效果。可移植 。应用一套源代码即可部署到多种平台,而不会出现意外状况。开源 。它是一个齐全开源的工具包,您无需领取许可费,也不必为相干开发工具付费。事实证明 Flutter 深受欢送: 迄今为止已有超过 70 万款应用 Flutter 打造的利用上架。Flutter 的使用者中既有 志存高远的小型初创公司,也不乏 有要害需要的大型成熟企业。Flutter 的价值还让 Google 外部团队受害,Google 课堂 等团队借助 Flutter 为挪动和 Web 用户提供优质解决方案。咱们还在其余开发者工具中增加了对 Flutter 的反对,这些工具包含 Google Ads、Google Maps、Google Pay,当然还有 Firebase。观看 Google 课堂与 Flutter 视频理解更多详情。 借助 Flutter,咱们将同一性能的代码量缩减了 66%…这意味着各个平台上的 bug 数量缩小,将来的技术负债也更低。 ...

February 23, 2023 · 3 min · jiezi

关于flutter:防抖与节流教你倾听时插话的技巧

本文内容次要翻译自issue 中国外大佬对防抖与节流的解释, 前面补充了本人的了解和总结。 什么是防抖与节流防抖和节流是解决“过于频繁”产生的事件的罕用技术。设想一下,你和敌人见面,敌人正在给你讲一个故事,但他们谈话时很难停下来。假如您想在可能的状况下不打断他们满足他们讲故事的兴致,同时还要回应他们所说的话。 (我晓得这可能有点做作,但请急躁期待!) 假如你们永远不能同时谈话。你有几个策略: 同步你能够在他们说完每句话时做出回应: 如果您的回复很短,这可能没问题。然而,如果您的答复较长,这可能会使他们很难讲完这个故事。所以这个策略不是很好。 防抖(Debounced)你能够等他们进行谈话。例如,如果他们进展的工夫足够长,您就能够开始回应: 如果你的敌人偶然会停下来,这个策略会很无效。然而,如果他们不停地说了几分钟,这基本不会让你回应: 节流(Throttled)您能够决定最多每分钟响应一次。在这里,您能够计算本人有多久没有谈话了。一旦你一分钟没有谈话,你就在敌人的下一句话之后插入你的回应: 如果您的敌人心愿您在他们讲故事时做出回应,但他们不会为您做这件事而制作进展,则此策略会很有帮忙。然而,如果他们两头进展了一会,但您仍在平白无故地期待,此时单方都没谈话,那就难堪了: 含意解释敌人的“句子”是按钮点击或键盘输入等事件。您的“回应”正在更新屏幕。 当用户做某事太快(例如打字)时,响应每个独自事件更新屏幕太慢。因而,您能够应用防抖或节流,要么期待用户进行输出(防抖),要么每隔一段时间更新一次屏幕,比方每秒一次(节流)。 补充举例游戏中:防抖就是 B 回城,以按下的最初一下为准。节流就是 QWER,按一下再按得等技能冷却能力再按。 生存中:假如电梯有两种运行策略 防抖和 节流,超时设定为 15 秒,不思考容量限度。 电梯第一个人进来后,15 秒后准时运送一次,这是节流 电梯第一个人进来后,期待 15 秒。如果过程中又有人进来,15 秒期待从新计时,直到 15 秒后开始运送,这是防抖 编程中:搜寻页面,用户间断输出,等停下来再去触发搜寻接口,这是防抖。 美团后盾位置服务不能过于频繁地调用后盾更新用户地位,必须以特定频率调用后端接口,这就是节流。 图解阐明 图片来着Dart/Flutter 防抖与节流 为什么防抖有 trailing 模式和 leading 模式? 起因:您可能会发现防抖事件在触发函数执行之前期待,直到事件进行如此迅速地产生,这让您感到恼火。(trailing edge 的状况),为什么不立刻触发函数执行,使其体现得与原始的未防抖处理程序齐全一样?于是就有了 leading edge 的状况。 总结防抖: n 秒后再执行该事件,若在 n 秒内被反复触发,则从新计时,所以防抖是操作时不执行不操作时执行。 节流: 高频事件触发,但在 n 秒内只会执行一次,所以节流会浓缩函数的执行频率,到时候了必须执行一次。 太棒了! 激励本人坚持到底。我心愿我为你投入的工夫减少了一些价值。 如果感觉文章对你有帮忙,点赞、珍藏、关注、评论,一键四连反对,你的反对就是我创作最大的能源。 ❤️ 本文原创听蝉 公众号:码里特地有禅 欢送关注原创技术文章第一工夫推送  ❤️ ...

February 20, 2023 · 1 min · jiezi

关于flutter:flutter系列之在flutter中使用导航Navigator

简介一个APP如果没有页面跳转那么是没有灵魂的,页面跳转的一个罕用说法就是Navigator,flutter作为一个最为优良的前端框架,Navigator必定是必不可少的,那么在flutter中如何应用Navigator呢? 一起来看看吧。 flutter中的NavigatorNavigator是flutter中用来导航的要害组件。咱们先来看下Navigator的定义: class Navigator extends StatefulWidgetNavigator首先是一个StatefulWidget,为什么是一个有状态的widget呢?这是因为Navigator须要在外部报错一些路由的信息,事实上Navigator中保留的就是一个栈构造的历史拜访过的widget。 咱们来看下它的构造函数,而后了解一下它外部的各个属性的含意: const Navigator({ Key? key, this.pages = const <Page<dynamic>>[], this.onPopPage, this.initialRoute, this.onGenerateInitialRoutes = Navigator.defaultGenerateInitialRoutes, this.onGenerateRoute, this.onUnknownRoute, this.transitionDelegate = const DefaultTransitionDelegate<dynamic>(), this.reportsRouteUpdateToEngine = false, this.observers = const <NavigatorObserver>[], this.restorationScopeId, })在这些属性中onGenerateRoute,pages,onGenerateInitialRoutes,transitionDelegate和observers这几个参数必须是非null。 首先是pages,pages是一个List对象: final List<Page<dynamic>> pages;这里的pages存储的就是历史访问信息,Navigator的所有操作都是围绕着pages来的。 如果咱们想在page切换的过程中增加一些动画,那么就能够用到transitionDelegate,如果咱们要弹出一些page的话,那么可能会心愿用到onPopPage callback办法来对pages list进行一些非凡解决。 另外initialRoute是须要第一个展现的route,Navigator还提供了两个办法用来在生成Route的时候进行触发:onGenerateRoute,onGenerateInitialRoutes。 Navigator提供了一系列的pop和push办法用来对路由进行跳转。 上面咱们将会通过一个具体的例子来对Navigator进行具体的解说。 Navigator的应用在这个例子中咱们会应用Navigator的两个最根本的办法push和pop来进行路由的切换。 先来看下push办法的定义: static Future<T?> push<T extends Object?>(BuildContext context, Route<T> route) { return Navigator.of(context).push(route); }push是一个静态方法,这意味着咱们能够通过应用Navigator.push来进行调用。 push办法须要传入两个参数,别离是context和route。 为什么会有context呢?这是因为Navigator是和context相关联的,不同的context能够有不同的Navigator。 Route就是要导入的路由。 能够看到办法外部实际上是调用了Navigator.of办法,最初返回的是一个Future对象。 咱们的例子是两个图片widget的简略切换。点击一个图像widget会调整到另外一个图像widget上,在另外一个图像widget上点击,会跳转回前一个widget。 咱们能够这样定义第一个widget: ...

February 20, 2023 · 1 min · jiezi

关于flutter:flutter系列之使用SliverList和SliverGird

简介在上一篇文章咱们解说SliverAppBar的时候有提到过,Sliver的组件个别都用在CustomScrollView中。除了SliverAppBar之外,咱们还能够为CustomScrollView增加List或者Grid来实现更加简单的组合成果。 明天要向大家介绍的就是SliverList和SliverGird。 SliverList和SliverGird详解从名字就能够看出SliverList和SliverGird别离是List和Grid的一种,他们和List与Grid最大的区别在于,他们能够管制子widget在main axis和cross axis之间的距离,并且能够通过Extent属性来管制子widget的大小,十分的弱小。 咱们先来看下这两个组件的定义和构造函数: class SliverList extends SliverMultiBoxAdaptorWidget { /// Creates a sliver that places box children in a linear array. const SliverList({ Key? key, required SliverChildDelegate delegate, }) : super(key: key, delegate: delegate);SliverList继承自SliverMultiBoxAdaptorWidget,它的构造函数比较简单,须要传入一个SliverChildDelegate的参数,这里的SliverChildDelegate应用的是delegate的办法来创立SliverList的子组件。 SliverChildDelegate是一个抽象类,它有两个实现类,别离是SliverChildBuilderDelegate和SliverChildListDelegate。 其中SliverChildBuilderDelegate是用的builder模式来生成子widget,在上一篇文章中,咱们构建SliverList就是应用的这个builder类。 SliverChildBuilderDelegate应用builder来生成子Widget,而SliverChildListDelegate须要传入一个childList来实现结构,也就是说SliverChildListDelegate须要一个确切的childList,而不是用builder来构建。 要留神的是SliverList并不能指定子widget的extent大小,如果你想指定List中的子widget的extent大小的话,那么能够应用SliverFixedExtentList: class SliverFixedExtentList extends SliverMultiBoxAdaptorWidget { const SliverFixedExtentList({ Key? key, required SliverChildDelegate delegate, required this.itemExtent, }) : super(key: key, delegate: delegate);能够看到SliverFixedExtentList和SliverList相比,多了一个itemExtent参数,用来管制子widget在main axis上的大小。 而后咱们再来看一下SliverGird: class SliverGrid extends SliverMultiBoxAdaptorWidget { /// Creates a sliver that places multiple box children in a two dimensional /// arrangement. const SliverGrid({ Key? key, required SliverChildDelegate delegate, required this.gridDelegate, }) : super(key: key, delegate: delegate);SliverGrid也是继承自SliverMultiBoxAdaptorWidget,和SliverList一样,它也有一个SliverChildDelegate的参数,另外它还多了一个gridDelegate的参数用来管制gird的布局。 ...

February 13, 2023 · 2 min · jiezi

关于flutter:借助-Flutter-跨平台特性连接-10-亿玩家-Flutter-开发者故事

由光子工作室及 Krafton 联结研发的 PUBG MOBILE 仍然放弃着极高的人气,目前寰球有 10 亿玩家,日沉闷 5,000 万 (不包含中国大陆地区)。从游戏策动伊始,团队就打算为各个平台的玩家们打造功能完善的社区模块。在 PUBG MOBILE 中,玩家们被空投到一个荒岛上,孤身奋战或与队友单干,致力与对手周旋,幸存到最初博得胜利。想要在这个游戏里 "吃鸡",玩家的麻利反馈和大局意识都很重要——而对负责开发游戏内社区模块的团队来说,这两点正好也是他们胜利的秘诀。 https://www.bilibili.com/vide... △ PUBG MOBILE 如何连贯 10 亿玩家 | Flutter 开发者故事 全平台一盘棋,大局意识很重要 负责 PUBG MOBILE 游戏社区模块的团队规模并不是很大,但服务的玩家群体却非常宏大,这也让团队对任何能提高效率的开发技术都非常敏感。2020 年下半年,当团队着手为社区模块寻找解决方案时,就在着眼寻找适合的 跨平台解决方案: 他们须要让社区模块能很不便地笼罩 Android 和 iOS 平台。 咱们测试的很多解决方案都存在这样那样的限度,但这些限度在 Flutter 中则不存在: 即使在引入了简单的业务逻辑后,Flutter 的性能体现依然非常优良。 胡明春,PUBG MOBILE 开发团队高级工程师 △ Flutter 打造的社区模块始终能保持稳定的帧率 团队抉择 Flutter 的另一个起因是它能很不便地 和现有的游戏进行整合。这也让社区模块在开发层面不至于和其余模块 "高度耦合",让团队能专一打造社区性能自身。 Flutter 能够很轻松地和现有的游戏进行整合,基本上照着官网文档操作就行,用不了多少工夫。 张海鹏,PUBG MOBILE 开发团队高级工程师 大幅升高代码量,麻利开发很重要 "一次编写,到处运行" 是 Flutter 跨平台个性带来的 "福利" 之一。除去一些平台特定的性能外,团队能够只用一个代码库就笼罩 Android 和 iOS 两个平台。这样做的另一个益处是能确保平台之间性能的一致性,在高强度迭代时这个益处更是十分重要。 自从采纳 Flutter 后,咱们发现能够将前端所需的开发工作量缩小 80%! 程建,PUBG MOBILE 开发团队高级工程师 △ 一次编写,到处运行 如果正在浏览本文的读者还没有体验过 Flutter 带来的这些劣势,那兴许还会心存顾虑: Flutter 好学吗? ...

February 9, 2023 · 1 min · jiezi

关于flutter:重识Flutter-用于解决复杂滑动视窗问题的Slivers-part1

前言在日常的开发工作中,仅仅应用ListView、ListView.builder等这样的滑动组件就能满足大部分的业务需要,在碰到较为简单的滑动页面时,加上Slivers系列中的几个罕用组件也简略的实现。这也就导致了一些敌人没有较为残缺的去理解Slivers系列。那么在重识Flutter这个专栏中,预计有5篇slivers相干的文章,从组件的应用到其背地的渲染原理,让咱们一起摸索Slivers的魅力吧! 视窗是什么? Sliver是什么?置信点进这篇文章的敌人,肯定会晓得ListView这样的滚动组件,滚动组件会提供一个区块,用于滚动的显示内容,但内容很多时,咱们只能看到可滚动内容中的局部内容。这个就是视窗(ViewPort),也就是列表的可视区域大小。例如一个ListView的显示区域高度为500像素,它列表项总高度可能远远超过500个像素,然而它的ViewPort仍为500像素。 那么Sliver是什么呢?咱们能够通过ListView.builder(),设置itemCount为null,构建一个有限的列表内容,只有当咱们滚动时,才会动静的去创立须要出现在视窗中的内容。这个就是Sliver,如果一个滚动组件反对Sliver模型,那么这个组件会将子组件分成很多个Sliver,只有当Sliver呈现在视窗中才会构建。 CustomScrollView像ListView、GridView等组件,在底层实现中都有着对应的Sliver,如SliverList、SliverGrid。Sliver版本的可滚动组件和非Sliver版本的可滚动组件最大的区别就是:Sliver版本的组件不蕴含滚动模型(Scrollable),组件本身不能滚动。 所以,如果想要应用Sliver系列的组件,就须要给它们增加滚动模型。Flutter提供了CustomScrollView,做为Sliver系列组件运行的容器。CustomScrollView次要的作用就是提供Viewport和一个公共的Scrollable,多个Sliver组件共用CustomScrollView的Scrollable,就达到了繁多滚动的场景。 CustomScrollView有着许多属性,其中最罕用的便是slivers,用来传入Sliver组件列表。就像这样: Scaffold( body: CustomScrollView( slivers: [ SliverList(/**/), SliverGrid(/**/), ], ), );有了CustomScrollView组件的帮忙,实现简单的滚动成果,如同不是那么艰难。 SliverList如果须要在一个界面创立多个列表,刚理解Flutter的敌人可能会应用Column中包裹多个ListView去实现,就像这样: 然而这样的成果必定不合乎需要,如果想要让它们一起滚动,或增加一些简单的动画,实现像这样的成果: 那么借助SliverList就能很简略的实现。 SliverList是Sliver Widget的一种,作用是将Widget排列在一个List中,应用SliverList须要定义delegate。Sliver delegate是用于形容应用哪种办法对组件进行渲染,通常有两种:static和builder。 在SliverList中,能够定义两种类型的delegate: SliverChildListDelegate:获取须要显示的组件列表。此列表中定义的组件将被立刻出现。不会有任何提早加载。SliverChildBuilderDelegate:获取将提早创立的小部件列表。这意味着随着用户滚动,残余的组件才会开始渲染。能够简略的把ListView了解为:CustomScrollView + SliverList + SliverChildListDelegate;把ListView.Builder了解为:CustomScrollView + SliverList + SliverChildBuilderDelegate。 在理解了SliverList须要定义的delegate后,那么应用它就和应用ListView一样简略: CustomScrollView( slivers: [ SliverList( delegate: SliverChildListDelegate([ Container( height: 50, color: Colors.primaries[0], ), ]), ), SliverList( delegate: SliverChildBuilderDelegate((BuildContext ctx, int index) { return Container( height: 50, color: Colors.primaries[index % Colors.primaries.length], ); }, childCount: 5), ), ], ),SliverGridSliverGrid与GridView一样,将组件以一行两个或一行多个的模式排列。它除了和SliverList一样须要定义一个失常的delegate之外,还须要传入gridDelegate,用于形容每行如何显示组件。就像这样:每行最多4个,每个组件的宽度是高度的1.5倍。 ...

February 9, 2023 · 2 min · jiezi

关于flutter:Flutter-37-新特性介绍后台isolate通道

Flutter 3.7 公布,自己对其中后盾isolate通道比拟感兴趣,急不可待翻译了下Aaron Clarke的文章,第一次翻译,有有余中央欢送各位大佬们评论区斧正,我将继续更新到本文,谢谢。 原文地址:Introducing background isolate channels | by Aaron Clarke | Flutter | Jan, 2023 | Medium 此时此刻,我很快乐地发表从 Flutter 3.7 开始开发人员能够在任意 isolate 中应用插件和平台通道了。 这是自 2018 年以来始终存在并且也是咱们排名最高的问题之一。它被升高了优先级,因为实现并不容易且已存在解决方案,只管很麻烦:始终在 root isolate(Flutter 提供的 isolate)中应用插件 . 然而,随着 Flutter 的日益成熟,越来越关注性能,俗话说“让它工作,让它正确,让它疾速”。 抉择实现这一特色有利于进步性能和易用性。 因而,思考带来的收益咱们决定实现这一个性。 如果您想理解如何应用此个性,请查看 GitHub 上的示例代码(PS: 原文示例代码不可用,这里我用另外一个官网大佬示例代替了。)。 用例为什么有人想在后盾 isolate 中应用插件呢?很显著,因为世上并不是所有代码都是用 Dart 编写的。社区多年来始终致力于应用插件来拜访代码(非 Dart 实现),例如 path_provider 找到长期目录的能力或 flutter_local_notifications 公布告诉的能力。 另外一个问题是:为什么有人在后盾线程中执行代码呢?因为有时您别无选择,库可能正调用后盾 isolate 回调,例如 android_alarm_manager_plus。或者某个利用可能正在进行大量计算,而开发人员不心愿这些计算影响 UI。 在我帮忙谷歌其余团队应用 Flutter 的过程中,随着产品的演进,最终会不可避免地遇到 root isolate 瓶颈。 因而,咱们须要确保在框架中优化,并为开发者提供工具使其在必要时做更少的事。 上面是后盾 isolate 一个人为的用例: 试想,一个应用程序可通过人工智能依据文本提醒生成高分辨率图像。用户之前创作都被存储在 Firebase Cloud 中,需要是用户能够用手机随时分享创作。该 Flutter 利用启动时会开启一个后盾 isolate 从 Firebase Cloud Store 下载 8K 文本提醒相干图片,将图像压缩至指定规格大小导出,保留到相册,最初导出实现并发送告诉。 ...

January 30, 2023 · 1 min · jiezi

关于flutter:Flutter-37-正式发布

新的 Flutter 稳定版退出了 Material 3 更新、iOS 平台优化及其他内容 新年伊始,由 Flutter 3.7 正式版来「打头阵」!咱们与整个 Flutter 社区成员们持续在 Flutter 3.7 中优化了框架,包含创立自定义菜单栏和层叠式菜单、更好的国际化工具反对、新的调试工具以及其余性能和个性等。 新的稳定版里,咱们在继续改良一些个性,例如全局文本抉择、Impeller 渲染速度、DevTools 以及始终以来都在优化的性能。让咱们一起来疾速摸索 Flutter 3.7 的新个性吧! 加强对 Material 3 的反对在 Flutter 3.7 中,以下的 widget 曾经进行了 Material 3 的适配: Badge、BottomAppBar、Filled 和 Filled Tonal 按钮、SegmentedButton、Checkbox、Divider、Menus、DropdownMenu、Drawer 和 NavigationDrawer、ProgressIndicator、Radio 按钮、Slider、SnackBar、TabBar、TextFields 和 InputDecorator、Banner。 你能够间接在利用中的 ThemeData 里设置 useMaterial3 来启用 Material 3。只有在残缺的色彩计划下能力展现出 Material 3 最残缺的细节,你能够应用新的 Material 主题构建器 生成你的主题配置,也能够通过 Flutter ThemeData 结构中的 colorSchemeSeed (色彩种子) 主动生成一整套的主题: MaterialApp( theme: ThemeData( useMaterial3: true, colorSchemeSeed: Colors.green, ), // …);若想理解 Flutter 在 Material 3 上的反对进度,你能够在 GitHub 上查看 flutter #91605 号议题。 ...

January 28, 2023 · 4 min · jiezi

关于flutter:Flutter监听安卓系统字体变化监听安卓系统深色模式切换

Flutter通过弱小的MediaQuery控件做到监听前设施的信息及其设施信息的动态变化 参考:Flutter 弱小的MediaQuery控件Flutter 小技巧之 MediaQuery 和 build 优化你不晓得的机密MediaQuery妙用Flutter官网文档 MediaQuery 一个简略的小案例import 'package:flutter/material.dart';import 'ui/HomePage.dart'; void main() { runApp(const MyApp());}class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), routes: { "/":(context) => const MyHomePage(title: '23') // 测试页面 }, initialRoute: '/', builder: (context, widget) { print('监听到安卓零碎字体大小变动'); print(MediaQuery.of(context).textScaleFactor); print('监听到安卓零碎主题深色模式切换'); print(MediaQuery.of(context).platformBrightness == Brightness.light ? '红色主题':'深色主题'); return MediaQuery( // 设置全局文字缩放因子为默认1.0,文字大小不随零碎变动而扭转 data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: widget! ); }, ); }}

January 27, 2023 · 1 min · jiezi

关于flutter:Exception-Problem-building-Android-application-see-above-error

Flutter 开发调试始终报错Could not locate aapt. Please ensure you have the Android buildtools installed.Exception: Problem building Android application: see above error(s). 打包所有都失常,就是Android Studio无奈运行安卓模拟器下面。 参考答复材料https://stackoverflow.com/questions/66596943/flutter-app-could-not-locate-aapt-while-building 我的解决办法:mac和windows零碎思路统一,都是删除Adnroid SDK装置目录中,/用户/xxxx/资源库/Android/sdk/build-tools中最新的tools(看本人我的项目以后用的那个)。删除之后从新更新Android SDK最新的build-tools。更新实现之后在flutter run进行尝试。

January 27, 2023 · 1 min · jiezi

关于flutter:Flutter-这一年2022-亮点时刻

回看 2022,瞻望 Flutter Forward2022 年,咱们十分兴奋的看到 Flutter 社区继续发展壮大,也因而让更多人体验到了令人难以置信的体验。每天有超过 1000 款应用 Flutter 的新挪动利用公布到 App Store 和 Google Play,Web 平台和桌面应用程序数量也大幅减少。 咱们心愿邀请你通过咱们行将进行的 Flutter Forward 流动来理解这一势头的继续和详情,咱们也打算通过哔哩哔哩平台上的「Flutter社区」帐号进行直播转播,详情 查看这里。 为所有平台构建精美体验2022 年 I/O 大会上,咱们推出了 Flutter 3,继对 Windows 桌面的反对进入稳定版之后,开始将 macOS 和 Linux 桌面端的反对也推动到了稳定版。并且,咱们首次重新整理公布了咱们的布局,咱们心愿 Flutter 的将来能够以挪动端为核心,并扩大到多个平台。 随着 Flutter 版本的演进和逐步成熟,咱们看到各行各业的公司都正在应用 Flutter 开发他们的利用,截止 5 月份的 I/O 大会,曾经有超过 50 万个利用应用 Flutter 公布。 供应链平安 软件供应链平安 (Supply Chain Security) 近年来成为常常被提及的话题,2022 年,Flutter 团队也 对软件供应链平安方面减少了投入。 4 月下旬,Dart 团队与 GitHub 单干,Dependabot 开始反对 pub.dev 上的 package 版本检测,10 月 7 日,GitHub 供应链平安也已开始反对 Dart 的开发者生态。同时,Flutter Cocoon 也已达到 SLSA 2 级规范的要求。 ...

January 20, 2023 · 1 min · jiezi

关于flutter:大年初四Flutter-Forward-中国社区直播活动与你不见不散

之前咱们预报过,2023 年 1 月 25 日 (年初四),Flutter 团队将在肯尼亚首都内罗毕举办 Flutter Forward 大会,并同时开启线上直播。本次流动将为展现最新的 Flutter 技术更新,包含一个主题演讲,以及多个技术演讲和线上问答, 全方位展现 Flutter 如何推动 UI 开发的倒退。 Flutter Forward 国内直播为了帮忙国内的开发者第一工夫理解到 Flutter 的最新动向,咱们打算在国内的渠道对本次流动进行直播转播,具体直播流动内容如下: 流动工夫2023 年 1 月 25 日 (年初四),23:00 - 00:30 演讲内容Flutter Forward 主题演讲 演讲嘉宾Flutter & Dart 产品组产品经理和用户体验总监,Tim SneathFlutter 产品经理,Leigha JarettFlutter 产品经理,Ander DoboDart 产品经理,Michael Thomsen哔哩哔哩平台直播直播间地址: https://live.bilibili.com/21565221 直播预约 (预约有奖:Flutter 吉祥物 Dash 小鸟,总 1 份): https://t.bilibili.com/752740250573340680 流动免责申明 咱们会尽最大致力为社区成员们提供良好的转播体验,同时请参会者务必体谅,如果产生任何问题导致流动转播勾销或无奈进行,咱们将不另行发文告诉,请通过官网的形式进行流动的参加: flutter.cn/urls/ff 交换群 因为群聊二维码生效较快,请关注 「Flutter 社区」公众号,回复关键字「FF流动」即可退出群聊。

January 19, 2023 · 1 min · jiezi

关于flutter:Dart中声明变量的方式和区别

在Dart中所有未初始化的变量默认值均为null。变量: var:var申明的变量能够是任何数据类型,动静指定。var变量一旦赋值,类型便会确定,则不能再扭转其类型。var变量编译时须要确定变量类型。dynamic:dynamic申明的变量能够是任何数据类型,动静指定。dynamic申明的变量能够在前期扭转赋值类型。dynamic变量运行时须要查看变量类型Object:Object 是Dart所有对象的根基类,也就是说所有类型都是Object的子类(包含Function和Null),所以任何类型的数据都能够赋值给Object申明的对象。常量: final:变量类型能够省略应用final申明的变量,它只能赋值一次,赋值能够是常量也能够是变量。final润饰的是一个最终的变量,不能再次赋值,否则会报错。也能够先申明再次赋值,然而只能赋值一次。运行时常量;const:变量类型能够省略const润饰常量,申明的时候就得赋值,只能赋值一次,赋值必须是常量。不能批改,不能再次赋值。编译时常量,必须定义的时候初始化;区别:能够把const 常量赋给 final 变量,反过来不能够。const 变量 是隐式 final 的类型.题外: late:显式申明一个非空的变量,但能够不初始化。空平安:定义变量时咱们能够指定变量是可空还是不可空;Dart空平安反对基于以下三条外围准则 默认不可空:除非您把变量显式生命为可空,否则它肯定是非空类型; 渐进迁徙:您能够自在地抉择何时进行迁徙,多少代码会进行迁徙; 齐全牢靠:Dart的空平安是十分牢靠的,意味着编译期间蕴含了很多优化;! 空值断言操作符? 示意变量是可空类型?. 右边如果为空返回 null,否则返回左边的值,该运算符罕用于避免空异样?? 右边如果为空返回左边的值,否则不解决,该运算符罕用于设置默认值

January 13, 2023 · 1 min · jiezi

关于flutter:Dart中Super关键的解读

应用场景: 继承Dart中非默认构造函数是不能被子类继承的,即父类的结构器不会被继承dart中的继承: 1、子类应用extends关键词来继承父类2、子类会继承父类外面可见的属性和办法 然而不会继承构造函数3、子类能复写父类的办法 getter和settersuper的作用: 1、Super能够拜访子类中的父类办法。如果子类和父类办法名称雷同,则能够应用Super关键字辨别和应用// 将调用或调用以后类的display()办法display(); // 将调用或调用父类的display()办法super.display();2、Super能够拜访父类构造函数// 两种语法// 2.17版本当前// 应用 super 关键字间接援用即可Widget({super.key,super.XXX,...})// 2.17版本以前// 当在Dart中应用继承的时候,须要调用父类的结构器进行初始化,须要先列出类本身的构造方法的参数,而后再把这些参数传给父类:Wdget({Key key,@required this.index}):super(key:key);

January 12, 2023 · 1 min · jiezi

关于flutter:Flutter中全局状态管理provider包的基本使用

首先引入provider库关上我的项目下pubspec.yaml dependencies: provider: ^6.0.4装置 flutter pub get关键点: 1、Provider外部的DelegateWidget是一个StatefulWidget所以能够更新且具备生命周期。2、状态共享是应用了 InheritedProvider 这个 InheritedWidget 实现的。3、奇妙利用 MultiProvider 和 Consumer 封装,实现了组合与刷新颗粒度管制。Provider罕用组件: ChangeNotifierProvider、MultiProvider、Provider、Consumer、Consumer2以下先介绍两种我正在用的:ChangeNotifierProvider用法1.ChangeNotifierProvider({Key key, @required ValueBuilder<T> builder, Widget child }) ChangeNotifierProvider<UserInfo>( create: (BuildContext context) { return UserInfo(); }, builder:(context,child){ }, child: ProviderMainApp(), ),2.ChangeNotifierProvider.value({Key key, @required T notifier, Widget child }) ChangeNotifierProvider<UserInfo>.value( value: UserInfo(), child: const MyApp(), )MultiProvider用法 MultiProvider( providers: [ ChangeNotifierProvider<UserInfo>.value( value: UserInfo(), ), ], child: const MyApp(), );拜访和批改数据 间接拜访数据Provider.of<UserInfo>(context, listen: false).username调用批改数据办法Provider.of<UserInfo>(context, listen: false).setname(str);

January 11, 2023 · 1 min · jiezi

关于flutter:Flutter异常监控-伍-关于异常监控框架设计的思考

前言最近浏览 Catcher、BugSnag、Rollbar 三个 Flutter 异样监控开源框架,文章链接如下: Flutter 异样监控 - 壹 | 从 Zone 说起 Flutter 异样监控 - 贰 | 框架 Catcher 原理剖析 Flutter 异样监控 - 叁 | 从 bugsnag 源码学习如何追溯异样产生门路 Flutter 异样监控 - 肆 | Rollbar 源码赏析 这篇文章将从实现性能,优缺点,设计思维等方面做个总结,不便开发中技术选型。 需要列表列举下认为比拟重点需要,并不示意框架所有需要只有这些。 性能比照所有上述需要次要体现在异样产生到发送过程中,大抵包含如下几个方面 CatcherBugsnagRollbar自定义 UI 显示异样是(4 种报告模式)不反对不反对异样解决线程main isolate对端决定子 isolate自定义包装过程局部反对不反对反对异样存储不反对对端存储Dart 侧存储自定义上报处理程序6 种1 种(自研)1 种(自研)异样门路生成追溯不反对主动 + 手动手动是否纯 Dart 实现Dart对端+DartDart对端异样解决不反对反对局部反对是否有自研后盾无有有反对平台全平台android,iosandroid,ios框架的好与坏如果问哪个最牛逼,我只能说:“没有不好的框架,只有乱用的人”。谁又不是个(某人心中的)宝宝呢?不同场景下谁都是本人的王者。 正确食用形式: 利用场景Catcher如果对异样 UI 显示和自定义上报要求很高,且反对全平台,能够选 Catcher。Bugsnag如果对端各平台 SDK 有深耕和技术积攒,能够参考 Bugsnag 来对立 Dart 端接口设计和主动埋点。Rollbar如果偏重性能可插拔,对 UI 性能要求高,重度 Dart 用户且将来须要反对全平台,能够选 Rollbar。论变与不变设计模式中最重要的准则是开闭准则,23 种设计模式都是以开闭准则为外围。 ...

January 11, 2023 · 2 min · jiezi

关于flutter:Flutter异常监控-肆-Rollbar源码赏析

一. Rollbar能够帮你解决哪些问题无特地阐明,文中Rollbar统指Rollbar-flutter1. 代码复用 Rollbar官网文档说是纯Dart实现,该特色意味着自带”代码复用”光环。 如图当接入端(Third-APP)调用Rollbar SDK时示意蕴含的网络(异样数据上传等)和存储(异样存储管理)可达到复用成果。 若Flutter异样监控框架非纯Dart实现(第三篇中Bugsnag),就存在代码无奈复用问题,如图,Dart-Crash-SDK是这层壳依赖对端SDK,最终导致各平台(android,ios,…)都须对端SDK(android-crash-sdk, ios-crash-sdk,…)适配,导致网络和存储逻辑对端SDK都须各自实现一遍,重大逻辑反复。 由此在做软件多端架构设计时,Dart侧可了解成是多平台公共代码汇合,如果存在多端逻辑性能代码齐全能够抽离到Dart侧以复用,缩小测试和人力老本。 2. 定制包装操作后面两篇文章咱们晓得,捕捉到原始异样后对其中的Error和StackTrace有相当局部的工作是对原始异样数据的包装再将包装类数据发送给对端或者后盾,不同框架包装过程是不一样的,如下图中Catcher框架包装后类对象是Report,Bugsnag对异样进行两次包装,第一次是BugsnagError,第二次是BugsnagEvent。 这很好了解,因为对于同一事物不同框架的需要是不一样的,不同需要注定了不同的包装行为。原始异样数据就像一条鱼,口味油腻的Catcher抉择清蒸,重口味的Bugsnag抉择红烧,不同框架就是不同口味的吃鱼人。而Rollbar 将包装行为抽象化,将原始的鱼以某种形式提供给你,让你享受自在烹饪乐趣。 3. 线程切换异样产生后有很多耗时操作,如原始异样数据包装中存在读取额定字段,异样的存储,查问,加密,上报等。耗时操作都在main isolate 中做, 势必会影响到main isolate的UI 构建等行为,异样数据量比大时UI会有卡顿状况,就像图中状况, Rollbar反对将异样耗时解决操作交给子isolate(crash isolate),让main isolate放弃专一做UI构建等以进步利用的晦涩度。 4. 追溯生成门路该需要与第三篇Flutter异样监控 - 叁 |从bugsnag源码学习如何追溯异样产生门路 雷同 该需要目标是能残缺记录用户操作的整个行为门路,这样达到清晰领导用户操作过程,对问题的定位很有帮忙。能够了解成一个小型的埋点零碎,只是该埋点零碎只是针对异样来做的。区别在代码层面实现,bugsnag中有主动增加和手动增加门路两种状况,Rollbar中只有手动增加,然而手动增加分类更加细化,比方图中将Breadcrumb结构过程被分成Breadcrumb.error、Breadcrumb.navigation、Breadcrumb.widget、Breadcrumb.log 对应不同图标事件。 话说,追溯异样生成门路需要是标配么? 目前看Bugsnag和Rollbar都有实现。 二. 如何应用将包增加到您的文件中:pubspec.yamldependencies: rollbar_flutter: ^0.3.0-beta运行 flutter pub get代码中配置: import 'package:rollbar_flutter/rollbar.dart';Future<void> main() async { const config = Config( //accessToken到https://rollbar.com/注册获取 accessToken: 'YOUR-ROLLBAR-ACCESSTOKEN', package: 'rollbar_flutter_example'); await RollbarFlutter.run(config, () { runApp(const MyApp()); });}要求Dart SDK >= 2.7.0Flutter >= 1.20.0A Rollbar account三. 原理解析Rollbar是Flutter异样框架,当然少不了读这类源码套路,间接拿出第三篇文章中的通用浏览门路, 依照如下流程一步步走: ...

January 10, 2023 · 2 min · jiezi

关于flutter:flutter系列之flutter中listview的高级用法

简介个别状况下,咱们应用Listview的形式是构建要展现的item,而后将这些item传入ListView的构造函数即可,通常状况下这样做是够用了,然而不排除咱们会有一些其余的非凡需要。 明天咱们会来解说一下ListView的一些高级用法。 ListView的惯例用法ListView的惯例用法就是间接应用ListView的构造函数来结构ListView中的各个item。 其中ListView有一个children属性,它接管一个widget的list,这个list就是ListView中要出现的对象。 咱们来结构一个领有100个item的ListView对象: class CommonListViewApp extends StatelessWidget{ const CommonListViewApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ListView( children: List<Widget>.generate(100, (i) => Text('列表 $i')), ); }}下面的例子中,咱们简略的应用List.generate办法生成了100个对象。 在item数目比拟少的状况下是没有任何问题的,如果item数目比拟多的状况下,间接将所有的item都取出来放在ListView中就不太事实了。 幸好,ListView还提供了一个ListView.builder的办法,这个办法会按需进行item的创立,所以在item数目比拟多的状况下是十分好用的。 还是下面的例子,这次咱们要生成10000个item对象,而后将这些对象放在ListView中去,应该如何解决呢? 因为这次咱们要应用builder,所以没有必要在item生成的时候就创立好widget,咱们能够将widget的创立放在ListView的builder中。 首先,咱们构建一个items list,并将其传入MyApp的StatelessWidget中: MyApp( items: List<String>.generate(10000, (i) => '列表 $i'), )而后就能够在MyApp的body中应用ListView.builder来构建item了: body: ListView.builder( itemCount: items.length, prototypeItem: ListTile( title: Text(items.first), ), itemBuilder: (context, index) { return ListTile( title: Text(items[index]), ); }, )ListView.builder是举荐用来创立ListView的形式,下面的残缺代码如下: import 'package:flutter/material.dart';void main() { runApp( MyApp( items: List<String>.generate(10000, (i) => '列表 $i'), ), );}class MyApp extends StatelessWidget { final List<String> items; const MyApp({Key? key, required this.items}) : super(key: key); @override Widget build(BuildContext context) { const title = 'ListView的应用'; return MaterialApp( title: title, home: Scaffold( appBar: AppBar( title: const Text(title), ), body: ListView.builder( itemCount: items.length, prototypeItem: ListTile( title: Text(items.first), ), itemBuilder: (context, index) { return ListTile( title: Text(items[index]), ); }, ), ), ); }}创立不同类型的items看到这里,可能有同学会问了,ListView中是不是只能创立一种item类型呢?答案当然是否定的。 ...

January 3, 2023 · 2 min · jiezi

关于flutter:为什么选择Flutter-进行跨平台开发

Flutter 初见本文概述:文章以跨平台开发为背景,探讨了跨平台开发技术的倒退历史,以及Flutter 的劣势。思维导图: 学习跨平台技术的必要性传统挪动端原生开发弊病: 传统的原生开发须要保护Android 、IOS 两个平台;应用Flutter 进行挪动端开发的长处: Flutter 为跨平台的UI 框架,真正做到一套代码多端应用,减少代码复用,易保护;在于求职中,若具备跨平台开发能力,将具备更强的市场竞争力;跨平台开发倒退历史:第一阶段:纯原生开发开发成本大:须要保护Android 与 IOS 两套代码;动态化需要:需要发生变化时,纯原生利用大多须要通过版本升级来更新内容。 短少热更新原生开发不可代替的劣势:性能劣势混合开发呈现的起因: 当硬件设施性能晋升,反哺开发模式,即,可就义一部分性能应用混合开发,以缩小开发成本。第二阶段:基于WebView 的 PhoneGap & Cordova(H5 )呈现机会: 在20008 年提出 PhoneGap,其采纳 HTML + CSS + JavaScript,依靠于Android 内置WebView 实现混合开发,声称靠近原生性能。后衍生出Cordova,这个是从PhoneGap 中抽离出的外围代码,因为收买起因,所以改了名字,其实还是一套代码;技术现状: 除了简略页面外,在思考性能时,根本不会采纳此种跨平台伎俩。底层机制: 在Android 中应用WebView 加载 HTML,HTML传给 JS 一个JavaInterface, Js 通过传入的JavaInterface 进而调用到Android 上的代码。图示: 外围代码:HTML 要与原生进行交互 Java 代码:应用WebView 加载 HTML,HTML传给 JS 一个JavaInterfacewebview.addJavaInterface(new AndroidPlatform(this),"android");Js 代码:Js 通过传入的JavaInterface 进而调用到Android 上的代码。<button type= "button" onclick = "android".toast('在JS 中,通过传入的JavaInterface 调用Android 平台的代码(toast)')> 按钮</button>AndroidPlatform.classpublic class AndroidPlatform{    private Context mContext;        public AndroidPlatform(Context context){//结构        mContext = context.getApplicationContext();   }        @JavascriptInterface    public void toast(String msg){        Toast.makeText(mContext,msg,Toast.LENGTH_SHORT).show();   }}技术长处: ...

December 27, 2022 · 2 min · jiezi

关于flutter:1-月-25-日见|Flutter-Forward-活动日程表正式发布

2023 年 1 月 25 日 (正月初四),咱们将在肯尼亚首都内罗毕举办 Flutter Forward 大会,并同时开启线上直播。本次流动将展现最新的 Flutter 技术更新,包含一个主题演讲以及多个技术演讲和线上问答,全方位展现 Flutter 如何推动 UI 开发的倒退,加入咱们的流动,看看将来几年的 Flutter 会如何持续构建精彩! https://www.bilibili.com/vide... 流动日程表本流动将于北京工夫 1 月 25 日 22:30 开始预热,正式 Keynote 演讲于 23 点正式开始,一个半小时之后完结,预热期间和 Keynote 开始后不久能够开始参加线上问答。流动将在北京工夫的第二天凌晨 12:45 正式完结。 下方所述工夫均为 北京工夫: 22:30 - 23:00 Flutter Keynote 预热“早鸟”提前获知流动独家信息,并提前参加线上问答,与 Flutter 团队互动。 主持 & 演讲者: Flutter & Dart 团队开发者关系工程师,John RyanFlutter 框架软件工程师,Kate Lovett23:00 - 00:30 Flutter Forward 主题演讲最新产品更新、最新技术演示、特邀嘉宾演讲,还有更多! 演讲嘉宾: Flutter & Dart 产品组产品经理和用户体验总监,Tim SneathFlutter 产品经理,Leigha JarettFlutter 产品经理,Ander DoboDart 产品经理,Michael Thomsen00:00 - 00:45 #AskFlutter 直播应用 #AskFlutter 发推发问,就有可能失去现场嘉宾们的答复! ...

December 23, 2022 · 1 min · jiezi

关于flutter:邀请参与第四季度-Flutter-开发者调查

本次调研会较为具体地理解大家对 Flutter 框架、开发语言、package 生态 (包含 Firebase package)、IDE 插件以及 Material Design / Cupertino 系列 widget 的应用体验等多个方面的满意度。您能够随时来到问卷页面,并在不便的时候返回持续作答,但请留神 本次调研将于 2022 年 12 月 23 日截止。 调查表链接:https://google.qualtrics.com/jfe/form/SV_cPlOPuHVF6HGzhI?Q_Language=ZH-S&Source=China_community

December 22, 2022 · 1 min · jiezi

关于flutter:flutter系列之移动端手势的具体使用

简介之前咱们介绍了GestureDetector的定义和其提供的一些根本的办法,GestureDetector的益处就是能够把任何一个widget都赋予相似button的性能。 明天将会通过几个具体的例子来解说一下GestureDetector的具体应用。 赋予widget能够点击的性能个别状况下,咱们的一般widget,比方文本是不能进行交互的,然而如果将其用GestureDetector进行包装之后,就能够将其假装成为一个button。 比方咱们有这样一个伪装成button的Container: Container( padding: const EdgeInsets.all(12.0), decoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.circular(8.0), ), child: const Text('My Button'), )这个Container的实质是一个Text,这个Container自身是没有交互性能的,那么如何对其增加交互性能呢? 最简略的方法就是将其应用GestureDetector包装起来,如下所示: GestureDetector( // The custom button child: Container( padding: const EdgeInsets.all(12.0), decoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.circular(8.0), ), child: const Text('My Button'), ), )接下来咱们还要为其增加对应的手势,这里咱们增加一个onTap办法, GestureDetector( onTap: ()=> showDialog<String>( context: context, builder: (BuildContext context) => AlertDialog( title: const Text('根本手势'), content: const Text('这是根本的手势,你学会了吗?'), actions: <Widget>[ TextButton( onPressed: () => Navigator.pop(context, 'Cancel'), child: const Text('Cancel'), ), TextButton( onPressed: () => Navigator.pop(context, 'OK'), child: const Text('OK'), ), ], ), ), ...这里onTap会调用一个showDialog来弹出一个对话框,运行之后后果如下: ...

December 19, 2022 · 2 min · jiezi

关于flutter:Flutter-for-Web-首次首屏优化JS-分片优化

作者:马坤乐(坤吾) Flutter for Web(FFW)从 2021 年公布至今,在国内外互联网公司曾经失去较多的利用。作为 Flutter 技术在 Web 畛域的无力裁减,FFW 能够让相熟 Flutter 的客户端同学间接上手写 H5,复用 App 端代码高效撑持业务需要;在 App 侧 FFW 也可作为 Flutter 动静下发的兜底计划。总的来说在业务和技术上 FFW 都具备相当的价值。 然而在应用 FFW 时有一个显著的问题:其编译产物 main.dart.js 较大,初始的 Hello world 工程编译后产物 js 大小为 1.2 MB,增加业务代码后 js 的大小还会持续减少。在阿里卖家的内容外投业务中,3 个页面的工程 js 大小为 2.0 MB,js 文件过大间接的影响就是页面首次首屏加载的速度。针对 js 的大小有较多优化办法,本文次要记录 main.dart.js 分片优化计划的实现。 1.计划总览 页面 js 加载速度晋升个别从两个角度思考: 缩小 js 文件大小晋升 js 加载效率对应到 js 分片计划,次要通过如下两点晋升加载速度: 按需加载:在工程中存在多个页面时,不管关上哪个页面都须要加载残缺的main.dart.js,而这里蕴含了很多不须要的页面代码。如果将各个页面的代码拆分只加载以后页面所须要的代码,则可缩小 js 文件体积,而且当其余页面越多逻辑越简单时,其晋升的成果越显著。 并行加载:将 js 分片后会生成多个大小不一的 js 文件,在带宽短缺的状况下如果应用并行加载则能够节俭较小的分片加载工夫。 注:js 文件压缩在线上部署的时候会主动解决,这里不做解决。 ...

December 15, 2022 · 5 min · jiezi

关于flutter:Flutter桌面开发-windows插件开发

Flutter桌面开发 - windows插件开发Flutter桌面开发 - windows插件开发 前言咱们都晓得,Flutter的定位更多是作为一个跨平台的UI框架,对于原生平台的性能,开发过程中常常须要插件来提供。可怜的是Windows的生态又极其不残缺,插件开发必不可少。但网上windows的文章少之又少,所以本篇文章,咱们一起来聊聊插件开发的一些技巧。插件介绍Flutter的插件次要分两种:package和plugin。 Package是纯dart代码的库,不波及原生平台的代码;Plugin是原生插件库,是一种非凡的Package。Plugin须要开发者别离在各原生平台实现对应的能力。 其中Plugin是咱们要着重讲的,既然是原生平台实现,那跟dart层就势必须要通信。Flutter Plugin的通信次要有:methodChannel、eventChannel、basicMessageChannel。 MethodChannel:同步调用的通道,调用后能够通过result返回后果。能够 Native 端被动调用,也能够Flutter被动调用,属于双向通信。这种通信形式是咱们日常开发中为最罕用的形式, 关键点是Native 端的调用须要在主线程中执行。EventChannel:异步事件告诉的通道,个别是Native端被动发出通知,Flutter接管通信信息。BasicMessageChannel:长链接的通道,双端能够随时收回音讯,对方收到音讯后能够应用reply进行回复。个别罕用于须要双向通信可不晓得何时须要发送的场景。 windows插件编写Flutter Android的生态算是比拟残缺的,而且网上95%的插件文章,都是以挪动端为主,对于不相熟Windows开发的同学极度不敌对。因而本篇文章咱们不讲Android端的实现,重点讲Windows端的实际,不过我也不是C++技术栈的,只能浅浅分享我踩过的坑。 如何创立通信通道?// MethodChannelvoid XXXPlugin::RegisterWithRegistrar( flutter::PluginRegistrarWindows* registrar) { // 创立一个MethodChannel auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>( registrar->messenger(), "usb_tool", &flutter::StandardMethodCodec::GetInstance()); // 创立插件对象 auto plugin = std::make_unique<XXXPlugin>(); // 把通道设置给插件,同时传入音讯的解决入口 channel->SetMethodCallHandler( [plugin_pointer = plugin.get()](const auto& call, auto result) { plugin_pointer->HandleMethodCall(call, std::move(result)); });}// EventChannel// 创立事件流解决对象auto eventHandler = std::make_unique<StreamHandlerFunctions<EncodableValue>>( [plugin_pointer = plugin.get()]( const EncodableValue* arguments, std::unique_ptr<EventSink<EncodableValue>>&& events) -> std::unique_ptr<StreamHandlerError<EncodableValue>> { return plugin_pointer->OnListen(arguments, std::move(events)); }, [plugin_pointer = plugin.get()](const EncodableValue* arguments) -> std::unique_ptr<StreamHandlerError<EncodableValue>> { return plugin_pointer->OnCancel(arguments); });// 创立EventChannel对象auto eventChannel = std::make_unique<flutter::EventChannel<flutter::EncodableValue>>( registrar->messenger(), eventChannelName, &flutter::StandardMethodCodec::GetInstance());// 把通道设置给插件eventChannel->SetStreamHandler(std::move(eventHandler));最初咱们还须要把插件注册进我的项目中registrar->AddPlugin(std::move(plugin)); ...

November 29, 2022 · 2 min · jiezi

关于flutter:flutter系列之在flutter中使用流式布局

简介咱们在开发web利用的时候,有时候为了适应浏览器大小的调整,须要动静对页面的组件进行地位的调整。这时候就会用到flow layout,也就是流式布局。 同样的,在flutter中也有流式布局,这个流式布局的名字叫做Flow。事实上,在flutter中,Flow通常是和FlowDelegate一起应用的,FlowDelegate用来设置Flow子组件的大小和地位,通过应用FlowDelegate.paintChildre能够更加高效的进行子widget的重绘操作。明天咱们来具体解说flutter中flow的应用。 Flow和FlowDelegate先来看下Flow的定义: class Flow extends MultiChildRenderObjectWidgetFlow继承自MultiChildRenderObjectWidget,说它外面能够蕴含多个子widget。 再来看下它的构造函数: Flow({ Key? key, required this.delegate, List<Widget> children = const <Widget>[], this.clipBehavior = Clip.hardEdge, }) : assert(delegate != null), assert(clipBehavior != null), super(key: key, children: RepaintBoundary.wrapAll(children));能够看到Flow中次要有三个属性,别离是delegate,children和clipBehavior。 children很好了解了,它就是Flow中的子元素。 clipBehavior是一个Clip类型的变量,示意的是如何对widget进行裁剪。这里的默认值是none。 最初一个十分重要的属性就是FlowDelegate,FlowDelegate次要用来管制Flow中子widget的地位变换。所以,当咱们在Flow中定义好子widget之后,剩下的就是定义FlowDelegate来管制如何展现这些子widget。 FlowDelegate是一个抽象类,所以咱们在应用的时候,须要继承它。 FlowDelegate有几个十分重要的办法: Size getSize(BoxConstraints constraints) => constraints.biggest;这个办法用来定义Flow的size,对于Flow来说,它的size是和子widget的size是独立的,Flow的大小通过getSize办法来定义。 接下来是getConstraintsForChild办法: BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) => constraints;getConstraintsForChild用来管制子widget的Constraints。 paintChildren用来管制如何绘制子widget,也是咱们必须要实现的办法: void paintChildren(FlowPaintingContext context);FlowDelegate还有两个办法,别离用来判断是否须要Relayout和Repaint,这两个办法的参数都是FlowDelegate: bool shouldRelayout(covariant FlowDelegate oldDelegate) => false;bool shouldRepaint(covariant FlowDelegate oldDelegate);Flow的利用有了下面的介绍,咱们基本上曾经理解如何构建Flow了,接下来咱们通过一个具体的例子来加深对Flow的了解。 ...

November 28, 2022 · 1 min · jiezi

关于flutter:Flutter-AppBar-使用-TabBar且去掉-Title

应用 PreferredSizeclass TabBarTestView extends StatelessWidget { const TabBarTestView({super.key}); @override Widget build(BuildContext context) { return DefaultTabController( initialIndex: 1, length: 2, child: Scaffold( appBar: const PreferredSize( preferredSize: Size.fromHeight(kToolbarHeight), child: TabBar(tabs: <Widget>[ Tab(text: "Tab 1"), Tab(text: "Tab 2"), ]), ), body: TabBarView( children: [...], ), )); }}

November 22, 2022 · 1 min · jiezi

关于flutter:Flutter-实现简单-TextButton-的单选-Toggle-效果

成果演示 页面class _TagsState extends State<Tags> { final int _tagsNum = 8; late List<bool> _selections; // 选中状态 List @override void initState() { super.initState(); // 初始化选中状态 List _selections = List.generate(_tagsNum, (_) => false); // 默认第一个 Tag 是选中状态 _selections[0] = true; } @override Widget build(BuildContext context) { return Wrap( children: <Widget>[ ...List.generate( _tagsNum, (index) => SelectableButton( style: TextButton.styleFrom( // null 即 default 色彩 foregroundColor: _selections[index] ? Colors.amberAccent : null, backgroundColor: _selections[index] ? Colors.blueAccent : null, ), onPressed: () { setState(() { // 简略粗犷把所有元素设为 false for (int i = 0; i < _selections.length; i++) { _selections[i] = false; } // 再把本身设 true _selections[index] = !_selections[index]; }); }, child: Text("Tag ${index + 1}"), ), ), ], ); }}SelectableButtonclass SelectableButton extends StatefulWidget { const SelectableButton({ super.key, required this.style, required this.onPressed, required this.child, }); final ButtonStyle? style; final Function()? onPressed; final Widget child; @override State<SelectableButton> createState() => _SelectableButtonState();}class _SelectableButtonState extends State<SelectableButton> { @override Widget build(BuildContext context) { return TextButton( style: widget.style, onPressed: widget.onPressed, child: widget.child, ); }}

November 5, 2022 · 1 min · jiezi

关于flutter:flutter-系列之flutter-中的幽灵offstage

简介咱们在应用flutter的过程中,有时候须要管制某些组件是否展现,一种办法是将这个组件从render tree中删除,这样这个组件就相当于没有呈现一样,然而有时候,咱们只是不想展现这个widget,然而这个组件还是存在的,并且能够承受键盘输入,还能够应用CPU。它和真正的组件惟一不同的就是他是不可见的。 这样的组件就叫做Offstage。 明天给大家具体介绍一下Offstage的应用。 Offstage详解咱们首先来看下Offstage的定义: class Offstage extends SingleChildRenderObjectWidget能够看到,Offstage是一个蕴含单个child的Widget。接下来看下它的构造函数: const Offstage({ Key? key, this.offstage = true, Widget? child }) : assert(offstage != null), super(key: key, child: child);Offstage次要蕴含两个属性,别离是示意是否是offstage状态的bool值offstage,如果offstage=true,那么Offstage的子child就会处于暗藏状态。这时候子child不会占用任何空间。 剩下的一个属性就是child了。 那么Offstage是如何管制child是否offstage的呢? 咱们看下它的createRenderObject办法: RenderOffstage createRenderObject(BuildContext context) => RenderOffstage(offstage: offstage);能够看到返回的是一个RenderOffstage对象,其中承受一个offstage参数。 如果深入研究RenderOffstage的话,能够看到他的paint办法是这样的: void paint(PaintingContext context, Offset offset) { if (offstage) return; super.paint(context, offset); }如果offstage是true的话,paint办法间接返回,不会进行任何的绘制。这也就是Offstage的机密。 Offstage的应用从下面解说的Offstage的构造函数咱们晓得,Offstage须要一个bool的offstage属性。所以这个offstage属性是能够变换的,从而触发offstage的不同状态。 因为offstage须要这样的一个状态,所以咱们在应用offstage的时候,一般来说是创立一个StatefulWidget,从而在StatefulWidget中放弃这样的一个offstage属性。 比方咱们创立一个OffstageApp,这是一个StatefulWidget,在它的createState办法中,返回一个State<OffstageApp>对象,在createState办法中,咱们定义一个_offstage属性。 通过应用这个_offstage,咱们能够创立Offstage如下: Offstage( offstage: _offstage, child: SizedBox( key: _key, width: 150.0, height: 150.0, child: Container( color: Colors.red, ), ), )这里咱们设置Offstage的offstage为刚刚设置的_offstage。 ...

October 31, 2022 · 1 min · jiezi

关于flutter:MobLink-for-Flutter

本插件是基于MobLink 对Flutter进行插件裁减反对。目标是不便Flutter开发者更不便地集成应用MobLink。Demo例子:https://github.com/MobClub/Mo... 开始集成引入插件 在 pubspec.yaml 文件中退出上面依赖`dependencies:moblink:mobcommonlib:`iOS端配置平台设置参考 iOS集成文档实现第一步增加配置里的XCode配置,配置初始化信息MOBAppKey 和 MOBAppSecret;第二步Mob后盾根本配置里的iOS端配置信息Android端配置平台设置参考 Android集成文档实现 第一步按Android集成文档中的第一点注册利用,申请Mob的 AppKey 和 AppSecret;第二步按Android集成文档中的第一点实现集成配置 1.关上我的项目根目录的build.gradle,在buildscrip–>dependencies 模块上面增加classpath 'com.mob.sdk:MobSDK:+',如下所示;buildscript { repositories { maven { url "https://mvn.mob.com/android" } ... } dependencies { ... classpath "com.mob.sdk:MobSDK:2018.0319.1724" }}2.在应用MobLink模块的build.gradle中,增加MobSDK插件和扩大,如下所示: // 增加插件apply plugin: 'com.mob.sdk'// 在MobSDK的扩大中注册MobLink的相干信息MobSDK { appKey "您的Mob-AppKey" appSecret "您的Mob-AppSecret" MobLink { uriScheme "您后盾配置的scheme" appLinkHost "您后盾开启AppLink时生成的Host" }}第三步在MainActivity中增加以下代码: //导入的包import com.mob.moblink.MobLink;// 必须重写该办法,避免MobLink在某些情景下无奈还原@Overrideprotected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); MobLink.updateNewIntent(getIntent(), this);} 第四步,调用隐衷接口时,须要将导入插件的example中的MainActivity中接口的代码复制到本人的MainActivity中去,否则隐衷接口的调用会有问题:第五步创立一个application继承FlutterApplication,在创立的application的onCreate中增加以下代码避免APP杀死过程后无奈进行场景还原: //导入的包import com.example.moblink.MoblinkPlugin;import com.mob.moblink.MobLink;//避免MobLink在APP杀死过程后无奈还原@Override public void onCreate() { super.onCreate(); MobLink.setRestoreSceneListener(new MoblinkPlugin.SceneListener()); }留神:Android的相干代码在Flutter层会报错,但不会影响我的项目的运行和MobLink性能的应用 ...

October 31, 2022 · 1 min · jiezi

关于flutter:Flutter支付宝授权插件

Flutter支付宝受权插件一个为支付宝受权SDK做的Flutter插件,同时反对Android、IOS 前言在一起漫部 App开发中,遇到支付宝SDK受权的性能需要,须要集成支付宝Android和IOS两端的SDK,咱们索性把它做成了一个独自的插件,开源到了pub.dev。 废话不多说,间接上效果图 开始应用在应用前强烈建议浏览官网接入指南 一、装置插件 1.在pubspec.yaml中配置 dependencies: alipay_auth: ^1.0.32.执行 执行 flutter pub get 3、导入头文件 import 'package:alipay_auth/alipay_auth.dart';二、开始受权 1、auth str强烈建议从后端接口获取 await AlipayAuthPlugin.aliPayAuth('your auth str');2、后果是 map 蕴含 AliPayAuth 的后果。后果还蕴含一个名为 platform 的内部文件,这意味着后果来自iOS或android。后果样本: {app_id: "",auth_code:"",result_code: SUCCESS,scope: auth_user,state: init,platform: android}3、查看支付宝装置 var result = await isAliPayInstalled();如果您想在 iOS 上查看支付宝装置的支付宝,请确保您已将支付宝增加到 info.plist 中的白名单中。 <key>LSApplicationQueriesSchemes</key><array> <string>alipay</string> <string>alipays</string></array>对于 iOS,您必须增加名为 alipay 的 url 架构。在 Xcode GUI 上:info.plist 中的 url_schem <array> <dict> <key>CFBundleTypeRole</key> <string>Editor</string> <key>CFBundleURLName</key> <string>alipay</string> <key>CFBundleURLSchemes</key> <array> <string>alipay_auth_example</string> </array> </dict></array>这里附上插件alipay_auth

October 27, 2022 · 1 min · jiezi

关于flutter:保护你的-Flutter-应用程序

爱护你的 Flutter 应用程序原文 https://medium.com/flutter-co... 如果本文对你有帮忙,请转发让更多的敌人浏览。 如果您不晓得须要更改哪些内容以及这些内容如何影响整个构建,那么爱护 Flutter 应用程序可能是一项工作,但在生产应用程序时,这是惟一最重要的事件。 爱护 Flutter 应用程序的平安应该是每个开发人员都必须认真对待的事件,因为这间接影响到应用程序的最终用户。他们的数据和通过 Internet 产生在您的应用程序之间的所有通信都可能受到各种攻打,意识到这些危险并采取措施防备这些危险应该是每个开发人员的责任。 Flutter + Security = ❤ 这里须要留神的一点是,我在本文中提到的所有内容都取决于您的应用程序是否须要它。您必须决定这对您的应用程序是否至关重要。首先,让咱们从一些根本的列表我的项目开始,而后转向更加技术性的列表我的项目。 应用受信赖的软件包,总体上应用较少的软件包(如果可能的话)大多数应用程序的性能或 UI 组件将依赖于内部包,确保所应用的包由受信赖的开发人员开发、保护良好并被相当多的人应用十分重要。这样做的起因是,在呈现问题的状况下,因为应用它的人数较多,所以它被提前发现。Dev 得分和受欢迎水平应该是一个很好的终点。 始终通过 HTTPS 进行通信如果您的应用程序与内部 API 和服务通信,请确保应用程序与近程服务器之间的通信是通过 HTTPS 进行的,以便数据在传输过程中被加密,并且在传输过程中没有内部黑客能够轻易拜访数据。简直所有在互联网上的货色都曾经迁徙到应用 HTTPS,所以这真的不应该再是一个选项,而是一种默认的做事形式。 HTTP vs HTTPS 正确的错误处理和消息传递有可能抛出异样的函数应该总是放在 try-catch 块中,这样就不会给用户带来不可预感的应用程序解体。除此之外,向用户显示有用的错误信息也是一个很好的做法,然而始终不要显示谬误的确切细节,因为这些信息可能/能够很容易地用来找到破绽。 import 'package:flutter/material.dart';Future<dynamic> functionThatThrowsException() async { // some code throw Exception('Could not perform operation.');}Future<void> testFunction() async { try { var x = await functionThatThrowsException(); // do something with x } catch (e) { debugPrint(e.toString()); }}Try Catch with Flutter当 Flutter 应用程序生产公布,如果产生谬误,灰色屏幕显示给用户,这能够从用户的观点令人丧气。因而,显示一个有用的谬误小部件/屏幕可能是简化用户体验的好办法。 ...

October 26, 2022 · 3 min · jiezi

关于flutter:flutter系列之永远不用担心组件溢出的Wrap

简介咱们在flutter中应用可能蕴含多个child的widget的时候,常常会遇到超出边界范畴的状况,尤其是在Column和Row的状况下,那么咱们有没有什么好的解决办法呢?答案就是明天咱们要解说的Wrap。 Row和Column的窘境Row和Column中能够蕴含多个子widget,如果子widget超出了Row或者Column的范畴会呈现什么状况呢? 咱们以Row的状况举个例子: Widget build(BuildContext context) { return Row( textDirection: TextDirection.ltr, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ YellowBox(), YellowBox(), Expanded( child: YellowBox(), ), YellowBox(), ], ); }下面的例子中,咱们在Row中增加了几个YellowBox,YellowBox是一个width=100,height=50的长方形: Widget build(BuildContext context) { return Container( width: 100, height: 50, decoration: BoxDecoration( color: Colors.yellow, border: Border.all(), ), ); }运行下面的代码,咱们能够失去这样的界面: 如果在Row中多增加几个YellowBox会有什么成果呢? 咱们在下面的Row中多增加一个yellowBox: Widget build(BuildContext context) { return Row( textDirection: TextDirection.ltr, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ YellowBox(), YellowBox(), Expanded( child: YellowBox(), ), YellowBox(), YellowBox(), ], ); }运行能够失去上面的界面: ...

October 24, 2022 · 2 min · jiezi

关于flutter:了解-Flutter-开发者们的-IDE-使用情况

作者 / JaYoung Lee, UX Researcher at Google Google 的 Flutter 团队负责构建和保护 Android Studio (基于 IntelliJ-IDEA) 和 Visual Studio Code (VS Code) 的反对。咱们将代码补全、语法高亮、widget 编辑辅助、运行和调试等性能集成到这些 IDE 插件中,用于 Flutter 利用开发。Flutter 开发者们从一开始就有在应用这两种 IDE,Android Studio 以前比 VS Code 更受欢迎,不过 VS Code 近期在 Flutter 开发中的热度始终在稳步减少,最近甚至超过了 Android Studio,如下文图中所示。 为了更好地了解 Flutter 开发者在抉择 IDE 时的想法,Flutter UX 团队在 2022 年 5 月发展了针对此课题的特地调研。 在后文中,"Android Studio" 同时代表 "Android Studio" 和 "IntelliJ-IDEA"。 △ 图 1. 从 2021 年 8 月到 2022 年 7 月,应用每个 IDE 的 Flutter 开发者数量。图中能够看出 VS Code 在过来几个月中变得更受欢迎。 ...

October 21, 2022 · 2 min · jiezi

关于flutter:flutter系列之flutter中可以建索引的栈布局IndexedStack

简介之前咱们介绍了一个flutter的栈构造的layout组件叫做Stack,通过Stack咱们能够将一些widget叠放在其余widget之上,从而能够实现图像的组合性能,也是日常中最罕用的一种组件了。明天咱们要介绍的组件是Stack的远亲,叫做IndexedStack,它有什么性能呢?一起来看看吧。 IndexedStack简介从名字能够看出,IndexedStack是给Stack增加了一个index的性能,事实是否如此呢?咱们先来看一下IndexedStack的定义: class IndexedStack extends Stack 能够看到IndexedStack继承自Stack,它实际上是Stack的子类,所以之前介绍的Stack有的性能IndexedStack全都有,并且IndexedStack是对Stack的性能进行了加强。 咱们来看下它的构造函数: IndexedStack({ Key? key, AlignmentGeometry alignment = AlignmentDirectional.topStart, TextDirection? textDirection, StackFit sizing = StackFit.loose, this.index = 0, List<Widget> children = const <Widget>[], }) : super(key: key, alignment: alignment, textDirection: textDirection, fit: sizing, children: children);能够看到和Stack相比,IndexedStack多了一个index参数,然而这个参数并没有传入到super的构造函数中去,那么index到底是在哪里应用的呢? 别急,IndexedStack还重写了上面的两个办法,别离是createRenderObject和updateRenderObject: @override RenderIndexedStack createRenderObject(BuildContext context) { assert(_debugCheckHasDirectionality(context)); return RenderIndexedStack( index: index, alignment: alignment, textDirection: textDirection ?? Directionality.maybeOf(context), ); } @override void updateRenderObject(BuildContext context, RenderIndexedStack renderObject) { assert(_debugCheckHasDirectionality(context)); renderObject ..index = index ..alignment = alignment ..textDirection = textDirection ?? Directionality.maybeOf(context); }和Stack相比,IndexedStack在这两个办法中应用的是RenderIndexedStack,而Stack应用的是RenderStack。 ...

October 21, 2022 · 2 min · jiezi

关于flutter:Flutter-中的应用内购买

尽管咱们总是精心制作咱们的应用程序,但咱们并不总是让它们收费。除了将咱们的应用程序上传到Play商店收取费用外,另一种赚钱的形式是通过利用内购买。Flutter in_app_purchase(IAP)是一个第一方Flutter软件包,容许开发者在其应用程序中实现iOS上的App Store或Android上的Google Play的利用内购买。另外两个解决方案,flutter_inapp_purchase 和 purchases_flutter,也提供了相似的性能。 在本文中,咱们的指标是领导您应用 purchases_flutter 软件包。 purchases_flutter这是一个应用 RevenueCat 解决方案实现利用内购买的插件。 RevenueCat 是一家简化应用程序内购买实现的第三方机构。在应用官网的Flutter插件(in_app_purchase)时,须要在服务器上实现本人的逻辑来解决购买验证、订阅和勾销等流程。 这样做须要大量的逻辑工作,因而,代替计划能够很有吸引力,因为它们能够做很多沉重的工作。Purchases_flutter能够为你解决这个逻辑,因而在你的应用程序中实现利用内购买更容易。RevenueCat的服务器将解决购买验证以及所有两头逻辑和中间件。 与利用内购买的其余实现相似,您须要在 Play Store 和 App Store 上设置无效的利用内购买。 让咱们从 RevenueCat 开始在应用 RevenueCat 之前,您必须注册 RevenueCat。不要胆怯。如果您从该利用取得的月支出低于 10000 美元,RevenueCat 是收费的。 注册后,导航到 RevenueCat 仪表板,而后从名为 Projects 的顶部导航菜单的下拉列表中增加一个新我的项目。 在我的项目仪表板的右边菜单中的我的项目设置>应用程序,抉择你要增加的应用程序的平台。 将利用增加到RevenueCat时,须要输出App name字段。其余的配置字段能够稍后再增加。 在你开始应用RevenueCat来获取产品之前,你必须在相应的商店中配置你的产品。 在Play Console中,您须要应用雷同的Product ID和雷同的试用和金额设置订阅。 两个订阅的详细信息应放弃不变。 装置要应用此插件,请将 purchase_flutter 增加为 pubspec.yaml 文件中的依赖项(并运行隐式 dart pub get): dependencies: purchases_flutter: ^3.0.0您当初应该能够导入 purchase_flutter。 import 'package:purchases_flutter/purchases_flutter.dart';如果你正在应用其余插件,比方 mobx,你可能会遇到与其余插件的类型抵触,这些插件的名称与 purchase_flutter 中定义的名称雷同。 如果产生这种状况,您能够通过增加导入别名来解决类型中的歧义,例如: import 'package:purchases_flutter/purchases_flutter.dart' as purchases;之后,你能够将 purchases_flutter 中的类型援用为 purchases.Foo,比方 purchases.PurchaserInfo。 ...

October 21, 2022 · 2 min · jiezi