跳到主要内容

写作助手

· 阅读需 3 分钟
Quany
软件工程师

https://ai.jsunc.com/

根据2025年最新行业测评和应用案例,以下AI Agent在不同场景中表现突出,综合功能、性能及用户反馈,推荐如下:


一、全能型AI Agent

  1. Manus

    • 核心优势:全能型AI代理,支持200+工具链,覆盖金融、教育、医疗等40余个领域,在GAIA基准测试中全球第一,效率提升最高达12倍。例如,15秒生成动态图表PPT,5分钟筛选15份简历。
    • 适用场景:企业复杂任务处理(如数据分析、报告生成)、跨行业自动化流程。
    • 市场表现:用户满意度85%,远超行业平均水平。
  2. 扣子(字节跳动)

    • 核心优势:支持多Agent协作、定时任务和工作流设计,插件扩展性强。例如,10~20分钟生成竞品分析报告,可直接用于会议决策。
    • 适用场景:运营方案制定、数据报表生成、跨平台自动化(如飞书多维表格、代码生成)。

二、垂直领域专家型AI Agent

  1. 文心一言(百度)

    • 核心优势:自然语言处理能力一流,擅长高质量文案生成(如文学作品、商业文案),交互效率高,多轮对话连贯性强。
    • 适用场景:内容创作、广告投放、宣传推广。
  2. 智谱清言

    • 核心优势:知识整合与推理能力突出,可解决复杂学术问题,交互逻辑清晰,支持多语言处理。
    • 适用场景:科研分析、学术探讨、技术文档撰写。
  3. Deepseek-R1(深度求索)

    • 核心优势:推理模型全球最高分(65.18分),擅长多轮对话和工具调用,数学与代码生成能力突出。
    • 适用场景:技术开发、数据分析、理科相关推理任务。

三、创新技术型AI Agent

  1. OpenAI Agents SDK

    • 核心优势:支持多Agent智能协作,内置工具集成和可视化追踪,在自动化办公场景中表现卓越(如自动操作网页完成购买、文件搜索)。
    • 适用案例:客户支持自动化、内容生成、传统系统改造(如无API系统的GUI操作)。
  2. Fellou(Agentic浏览器)

    • 核心优势:结合浏览器与工作流自动化,模拟人类操作完成信息搜索和报告生成,适合社交媒体运营。
    • 适用场景:网络调研、实时数据抓取、跨平台信息整合。

四、选型建议

  • 企业用户:优先选择Manus或扣子,兼顾效率与复杂任务处理。
  • 开发者/技术团队:OpenAI Agents SDK提供灵活的多Agent架构,适合定制化需求;Hunyuan-turbos(腾讯)作为国内第一基础模型,适合通用任务开发。
  • 个人用户/创作者:文心一言(文案生成)、智谱清言(学术支持)、Fellou(信息整合)更具针对性。

测评数据参考

  • 全球模型排行:GPT-4.5(71.88分)国际领先,Hunyuan-turbos(70.09分)国内第一,差距仅1.79分。
  • 场景成熟度:即时消息、文件管理等场景高度成熟(得分>40),旅游出行等复杂场景仍需技术突破。

如需更完整榜单或具体产品链接,可参考来源。

微信公众号

微信公众号

总部上班

· 阅读需 9 分钟
Quany
软件工程师

BrickHub 是一个专注于提升开发效率的代码生成与管理平台,其核心内容可总结如下:


1. 核心功能

  • 快速生成标准化代码:通过预定义的代码模板(称为 Bricks),用户可快速生成结构一致的代码,减少重复性工作,尤其适用于项目初始化(如 mason make flutter_project 生成 Flutter 项目框架)。
  • 模板生态
    • 发现模板:开发者可浏览并安装社区共享的 Bricks,覆盖多种场景(如特定框架、工具链等)。
    • 发布模板:支持用户创建并发布自定义 Bricks,促进知识复用。
    • 安装使用:通过集成工具(如 Mason CLI)直接调用模板生成代码。

2. 技术栈与工具

  • Mason CLI:核心命令行工具,用于创建、管理及执行 Bricks,提供类似脚手架的功能(如生成项目结构、模块代码等)。
  • Flutter 深度支持:示例中明确支持 Flutter 项目生成,暗示其对跨平台移动开发框架的优先适配。

3. 协作与治理

  • 开源与社区驱动:依托 GitHub 托管代码与模板,鼓励开发者贡献(通过 Request Access 可能涉及权限管理)。
  • 标准化流程
    • 文档化:提供详细使用指南(Read the Docs),降低学习成本。
    • 问题反馈:支持提交 Issue(Report an issue),完善模板质量。
    • 政策规范:制定明确的协作规则(Read the policy),保障模板合规性。

4. 目标用户场景

  • 个人开发者:快速启动新项目,避免重复配置。
  • 团队协作:通过统一模板确保代码风格与架构一致性,减少维护成本。
  • 开源贡献者:共享经过验证的最佳实践模板,扩大技术影响力。

5. 差异化价值

  • 一致性保障:强调生成代码的标准化,减少人为错误。
  • 生态闭环:从模板创建、发布到使用的完整链路,形成开发者工具生态。
  • 聚焦效率:通过“Supercharge Your Workflow”理念,直接解决开发流程中的低效环节。

6. 资源链接

  • 代码仓库:GitHub 托管核心代码与模板。
  • 文档:详细操作指南与 API 参考。
  • 政策:明确模板发布与使用的合规要求。

总结:BrickHub 通过构建可复用的代码模板生态,结合 Mason 工具链,为开发者提供快速、一致的代码生成服务,尤其适合追求效率与标准化的团队及开源项目。其围绕 Flutter 的深度整合,进一步巩固了在跨平台开发领域的实用价值。


Flutter 插件的实现原理

Flutter 插件的实现原理主要围绕 跨平台通信原生功能调用 展开。以下是其核心原理和实现机制的详细解析:


1. Flutter 插件的基本结构

Flutter 插件是一个混合模块,包含两部分:

  • Dart 代码:定义 API 接口,供 Flutter 应用调用。
  • 原生平台代码(Android/iOS):实现具体功能,通过通信机制与 Dart 交互。

例如,camera 插件的结构:

camera/
├── lib/ # Dart API
├── android/ # Android 原生实现
├── ios/ # iOS 原生实现
└── example/ # 示例代码

2. 跨平台通信机制:Platform Channels

Flutter 通过 Platform Channels 实现 Dart 与原生代码的通信,分为两种类型:

a. MethodChannel(方法调用)

  • Dart → 原生:调用原生方法并获取返回值。
  • 原生 → Dart:反向调用(较少使用)。

代码示例

// Dart 端调用原生方法
final methodChannel = MethodChannel('my_channel');
final result = await methodChannel.invokeMethod('getBatteryLevel');
// Android 端实现
public class MyPlugin implements MethodCallHandler {
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getBatteryLevel")) {
int battery = getBatteryLevel();
result.success(battery);
}
}
}

b. EventChannel(事件流)

  • 用于持续传输数据(如传感器数据、网络状态)。
  • 基于 Stream 机制实现。

代码示例

// Dart 端监听事件
EventChannel('sensor_channel').receiveBroadcastStream()
.listen((data) => print(data));
// Android 端发送事件
EventChannel.EventSink eventSink;
eventSink.success(sensorData); // 发送数据
eventSink.error("ERROR", "Sensor failed"); // 发送错误

3. 数据序列化与类型映射

  • 数据类型:基本类型(int, String, bool)、List、Map 等可通过 Platform Channels 传递。
  • 序列化:数据会被自动转换为平台原生类型:
    • Dart Map ↔ Android Bundle / iOS NSDictionary
    • Dart List ↔ Android ArrayList / iOS NSArray
  • 二进制数据:通过 ByteBuffer 传递(如图片、文件)。

4. 插件代码生成(Pigeon)

为了简化通信代码,Flutter 官方提供了 Pigeon 工具:

  1. 定义接口:编写一个 .dart 文件描述 API。
  2. 生成代码:自动生成 Dart 和原生代码的通信层。

示例

// api.dart
()
abstract class BatteryApi {
int getBatteryLevel();
}

运行 pigeon 生成 Android/iOS 和 Dart 的通信代码。


5. 原生模块注册

Android 端

  • MainActivityFlutterEngine 中注册插件:
    public class MainActivity extends FlutterActivity {
    @Override
    public void configureFlutterEngine(FlutterEngine flutterEngine) {
    flutterEngine.getPlugins().add(new MyPlugin());
    }
    }

iOS 端

  • AppDelegate 中注册:
    @UIApplicationMain
    class AppDelegate: FlutterAppDelegate {
    override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
    let controller = window.rootViewController as! FlutterViewController
    MyPlugin.register(with: controller.binaryMessenger)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    }

6. 线程模型

  • Dart 侧:所有调用默认在 UI 线程执行。
  • Android 侧:MethodChannel 调用默认在主线程,耗时操作需切换到子线程。
  • iOS 侧:默认在主线程,需通过 DispatchQueue 处理异步任务。

7. 插件依赖管理

  • 原生依赖:通过 build.gradle(Android)或 Podfile(iOS)声明。
  • 权限管理:在 AndroidManifest.xmlInfo.plist 中添加所需权限。

8. 常见插件实现模式

  1. 纯 Dart 插件:仅依赖 Dart 代码(如 path_provider 部分功能)。
  2. 混合插件:依赖原生代码(如 camerageolocator)。
  3. FFI(Foreign Function Interface):直接调用 C/C++ 代码(高性能场景)。

9. 调试与性能优化

  • 日志输出:使用 print(Dart)和 Log.d(Android)/ NSLog(iOS)。
  • 性能分析:避免频繁跨平台调用,批量传输数据。
  • 错误处理:统一处理原生异常并转换为 Dart 异常。

10. 插件实现的核心挑战

  • 平台差异:处理 Android 和 iOS 的 API 差异(如权限模型)。
  • 版本兼容性:适配不同 Flutter 和原生 SDK 版本。
  • 异步协调:确保 Dart 和原生代码的异步操作正确同步。

总结

Flutter 插件通过 Platform Channels 实现跨平台通信,结合自动代码生成工具(如 Pigeon)和原生模块化设计,使开发者能够无缝集成原生功能。理解其原理有助于:

  1. 开发高性能自定义插件。
  2. 调试复杂跨平台问题。
  3. 优化现有插件的兼容性和稳定性。

如需深入实践,可参考官方文档:Flutter Plugins and Packages

插件开发:Flutter FFI

开发 Flutter FFI 插件的步骤详解如下:


1. 创建 FFI 插件项目

使用以下命令创建一个支持 FFI 的插件模板:

flutter create --template=plugin_ffi --platforms=android,ios,linux,windows,macos my_ffi_plugin
cd my_ffi_plugin

项目结构包含:

  • lib/: Dart API 和绑定代码
  • src/: C/C++ 原生代码
  • android/ios/: 平台特定编译配置

2. 编写 C/C++ 原生代码

示例:实现加法函数

// src/native_add.c
#include "native_add.h"

int add(int a, int b) {
return a + b;
}
// src/native_add.h
#ifndef NATIVE_ADD_H
#define NATIVE_ADD_H

int add(int a, int b);

#endif

3. 生成 Dart FFI 绑定

3.1 配置 ffigen 工具

pubspec.yaml 中添加依赖:

dev_dependencies:
ffigen: ^8.2.0

创建 ffigen.yaml 配置文件:

name: 'NativeAddBindings'
description: 'Bindings for native_add.h'
output: 'lib/native_add_bindings.dart'
headers:
entry-points:
- 'src/native_add.h'

3.2 生成绑定代码

运行命令生成 Dart 绑定:

flutter pub run ffigen --config ffigen.yaml

生成的 lib/native_add_bindings.dart 包含函数签名和库加载代码。


4. 配置各平台编译

4.1 Android 配置

android/build.gradle 中添加 CMake 支持:

android {
externalNativeBuild {
cmake {
path "src/CMakeLists.txt"
}
}
}

创建 src/CMakeLists.txt

cmake_minimum_required(VERSION 3.10.2)
project(native_add)

add_library(native_add SHARED
native_add.c
)

4.2 iOS 配置

ios/CMakeLists.txt 中配置(若使用 CMake):

add_library(native_add STATIC
native_add.c
)

或直接在 Xcode 中导入 C 文件并设置头文件搜索路径。


5. 编写 Dart API 层

创建 lib/my_ffi_plugin.dart 封装调用:

import 'dart:ffi';
import 'native_add_bindings.dart';

class MyFfiPlugin {
static final DynamicLibrary _library = () {
if (Platform.isAndroid || Platform.isLinux) {
return DynamicLibrary.open('libnative_add.so');
} else if (Platform.isIOS || Platform.isMacOS) {
return DynamicLibrary.process();
} else if (Platform.isWindows) {
return DynamicLibrary.open('native_add.dll');
}
throw UnsupportedError('Platform not supported');
}();

static final NativeAddBindings _native = NativeAddBindings(_library);

int add(int a, int b) => _native.add(a, b);
}

6. 处理复杂类型和内存管理

示例:传递字符串

// src/native_utils.c
char* greet(const char* name) {
char* greeting = malloc(strlen(name) + 7);
sprintf(greeting, "Hello, %s!", name);
return greeting;
}

void free_greeting(char* ptr) {
free(ptr);
}

Dart 调用:

// 在绑定文件中生成对应函数
final Pointer<Utf8> Function(Pointer<Utf8> name) greet = _library
.lookup<NativeFunction<Pointer<Utf8> Function(Pointer<Utf8>)>>('greet')
.asFunction();

final void Function(Pointer<Utf8> ptr) freeGreeting = _library
.lookup<NativeFunction<Void Function(Pointer<Utf8>)>>('free_greeting')
.asFunction();

String sayHello(String name) {
final namePtr = name.toNativeUtf8();
final greetingPtr = greet(namePtr);
final greeting = greetingPtr.toDartString();
freeGreeting(greetingPtr);
calloc.free(namePtr);
return greeting;
}

7. 错误处理

C 层返回错误码

// src/native_math.h
typedef struct {
int result;
int error_code;
} MathResult;

MathResult safe_divide(int a, int b);

Dart 层处理错误

class MathError implements Exception {
final int code;
MathError(this.code);
String toString() => "MathError(code: $code)";
}

MathResult divide(int a, int b) {
final result = _native.safe_divide(a, b);
if (result.error_code != 0) {
throw MathError(result.error_code);
}
return result.result;
}

8. 编译与测试

编译插件

flutter build ios --release  # 编译 iOS
flutter build apk --release # 编译 Android

编写单元测试

void main() {
test('Test addition', () {
expect(MyFfiPlugin.add(2, 3), equals(5));
});

test('Test division error', () {
expect(() => MyFfiPlugin.divide(5, 0), throwsA(isA<MathError>()));
});
}

9. 平台适配注意事项

平台动态库扩展名加载方式
Android.soDynamicLibrary.open('libfoo.so')
iOS.aDynamicLibrary.process()
Windows.dllDynamicLibrary.open('foo.dll')
macOS.dylibDynamicLibrary.open('foo.dylib')

10. 高级技巧

  1. 异步调用:使用 Isolate 在后台线程执行耗时 C 函数。
  2. 结构体映射:通过 ffi.Struct 定义复杂数据结构。
  3. 回调函数:通过 Pointer<NativeFunction> 实现 Dart 到 C 的回调。
  4. 性能优化:使用 SIMD 指令或 GPU 加速(如 Metal/Vulkan)。

常见问题解决

  • 动态库找不到:检查编译输出路径,确保库被正确打包。
  • 符号未定义:在 C 代码中使用 extern "C" 避免 C++ 名称修饰。
  • 内存泄漏:使用 calloc.free() 或自定义释放函数。

通过以上步骤,你可以高效开发高性能 Flutter FFI 插件,无缝集成现有 C/C++ 库,同时保持跨平台兼容性。

微信公众号

微信公众号

关注当下

· 阅读需 3 分钟
Quany
软件工程师

根据2025年4月的最新数据,目前贷款利率最低的银行产品如下(以信用贷款为主):

一、最低利率产品前三名

  1. 农业银行——网捷贷
    年化利率2.85%起,需满足公积金缴纳满半年至两年(不同地区要求不同)或农行代发工资满1年,优质单位客户(如公务员、事业单位)优先。

  2. 邮储银行——邮享贷
    年化利率2.88%起(需使用优惠券),支持3年期先息后本还款,适用人群包括公务员、教师等优质客群,或邮储房贷客户。

  3. 招商银行——闪电贷
    年化利率2.9%起(需使用优惠券),还款方式灵活,适合社保/公积金缴纳满1年的优质单位客户。


二、四大行低息产品对比

  • 工商银行融e借:年化2.98%起,3年期先息后本或等额本息,适合公积金缴纳满1年的客户。
  • 中国银行随心智贷:年化3.2%起,针对白名单客户(如房贷还款满1年或公积金基数>4000元)。
  • 建设银行建易贷:年化3.15%起,负债要求宽松,优质单位客户可享受更低利率。

三、其他低息选择

  • 交通银行惠民贷:年化3.08%起,支持1年先息后本,适合交行代发工资或房贷客户。
  • 浦发银行浦闪贷:年化2.88%起(优惠券利率),长三角地区客户优先。
  • 江苏银行卡易贷/北京银行京E贷:年化3.0%起,针对公务员、事业单位等优质单位。

注意事项

  • 利率差异原因:最低利率通常针对特定群体(如优质单位、公积金客户),普通客户实际利率可能略高。
  • 隐性条款:部分产品需绑定保险(如工行车贷)、留存保证金(如邮储银行)或限制还款方式。
  • 市场动态:股份制银行(如招商、中信)和民营银行利率跨度较大,优质客户可议价。

建议根据自身资质(如公积金、职业类型)咨询银行客户经理获取精准报价,或通过助贷机构优化信贷结构。

微信公众号

微信公众号

Flutter 调试、日志管理与开发环境配置

· 阅读需 3 分钟
Quany
软件工程师

以下是关于 Flutter 调试、日志管理与开发环境配置 的综合指南,结合了多个来源的实践方法与工具建议:


一、调试方法与工具

  1. 基础调试工具

    • Flutter DevTools
      提供可视化调试界面,支持查看 Widget 树、性能指标、网络请求等:

      flutter run --debug  # 启动调试模式
      flutter pub global run devtools # 启动 DevTools

      通过浏览器访问 http://localhost:8080 即可分析应用状态、内存占用及渲染性能。

    • 断点调试
      在 IDE(如 Android Studio 或 VS Code)中直接添加断点,支持单步执行、变量监控及堆栈跟踪。

  2. 高级调试技巧

    • 转储应用层级结构
      使用 debugDumpApp() 输出 Widget 树、渲染树等信息,帮助定位布局问题。
    • 性能优化
      通过 DevTools 的 CPU ProfilerMemory 工具分析性能瓶颈,优化帧率与内存泄漏。
    • 网络调试
      结合 Reqable 抓包工具监控 HTTP 请求,支持 HTTPS 解密与请求重放。
  3. 可视化调试插件

    • UME
      字节跳动开发的调试工具,集成 UI 检查、颜色拾取、动画调试等功能,适合复杂界面问题定位。
    • Flutter Inspector
      实时修改 Widget 属性,支持布局边界检查与语义树分析。

二、日志管理实践

  1. 日志库推荐
    使用 logger 包实现结构化日志,支持分级输出(Verbose/Debug/Error 等)与自定义过滤:

    final logger = Logger(
    filter: ProductionFilter(), // 生产环境过滤非关键日志
    printer: PrettyPrinter(), // 美化输出格式
    );
    logger.i('User logged in'); // 信息级别日志
  2. 日志分级策略

    • 开发环境:启用 Level.verbose 输出详细日志,便于调试。
    • 生产环境:限制为 Level.warning 及以上,减少冗余信息。
  3. 异常捕获
    使用 try-catch 结合 logger.e() 记录错误堆栈,避免应用崩溃:

    try {
    // 业务代码
    } catch (e, stack) {
    logger.e('Operation failed', error: e, stackTrace: stack);
    }

三、开发环境配置

  1. 环境搭建步骤

    • 安装 Flutter SDK
      下载并解压 SDK,配置 PATH 环境变量。
    • 依赖检查
      运行 flutter doctor 安装缺失的 Android/iOS 工具链(如 JDK、Xcode)。
    • IDE 配置
      Android Studio 或 VS Code 需安装 Flutter/Dart 插件,启用代码补全与热重载。
  2. 多平台调试

    • Android:通过 AVD Manager 创建模拟器,支持 GPU 加速。
    • iOS:使用 Xcode 启动模拟器,需信任开发者证书。
    • Web:运行 flutter run -d chrome 调试浏览器端应用。

四、最佳实践总结

  • 调试优先级:优先使用 DevTools 可视化工具,复杂问题结合断点与日志回溯。
  • 日志规范:统一日志格式,避免 print() 滥用,关键操作需记录上下文。
  • 环境隔离:开发/生产环境采用不同配置,通过 kReleaseMode 区分。

logging****

微信公众号

微信公众号

Agent 产品设计

· 阅读需 6 分钟
Quany
软件工程师

在 Flutter 中实现 响应式缓存数据库,需要结合本地存储、缓存策略和响应式数据流机制。以下是基于多篇技术文档总结的完整方案及核心库推荐:


一、核心实现原理

响应式缓存数据库需满足以下特性:

  1. 数据持久化:支持本地存储(内存/磁盘);
  2. 缓存自动更新:数据变更时触发 UI 刷新;
  3. 网络请求优化:优先读取缓存,减少服务端请求;
  4. 离线支持:无网络时仍可读取缓存数据。

二、推荐技术栈与库

1. Hive + StreamBuilder(轻量级 NoSQL)

  • 优势
    • 内存级缓存速度,支持异步写入磁盘;
    • 内置响应式监听,可结合 StreamBuilder 实现自动刷新。
  • 实现示例
    // 初始化 Hive
    await Hive.initFlutter();
    final box = await Hive.openBox('cache');

    // 写入数据(自动触发缓存更新)
    box.put('key', 'value');

    // 响应式读取
    StreamBuilder(
    stream: box.watch(),
    builder: (context, _) => Text(box.get('key')),
    );

2. SQLite (sqflite) + Riverpod(结构化数据)

  • 优势
    • 支持复杂查询和事务处理;
    • 通过 ChangeNotifierStateNotifier 实现数据流监听。
  • 优化策略
    • 使用 flutter_cache_manager 缓存查询结果;
    • 结合 LRU 算法清理过期数据。

3. Realm(实时同步与高性能)

  • 场景:需要本地缓存与云端实时同步的应用(如聊天、实时协作)。
  • 特性
    • 数据变更时自动触发 Stream 更新;
    • 支持离线优先策略,网络恢复后同步差异数据。

三、实现步骤与最佳实践

1. 分层缓存设计

  • 内存缓存:使用 LinkedHashMap 实现 LRU 策略,存储高频访问数据;
  • 持久化缓存:通过 Hive/SQLite 存储结构化数据,确保应用重启后可读取。

2. 响应式数据流整合

  • 方案一StreamBuilder 监听数据库变化
    final stream = db.query('table').watch();
    StreamBuilder(stream: stream, builder: ...)
  • 方案二Riverpod 状态管理
    final cacheProvider = StreamProvider((ref) => db.watchChanges());
    ref.watch(cacheProvider).when(data: (data) => ...)

3. 缓存更新策略

  • 网络优先:首次加载从服务端获取数据并缓存,后续优先读取本地;
  • 定时失效:设置 TTL(Time-To-Live)自动刷新过期缓存。

4. 性能优化

  • 批量操作:减少数据库事务次数,使用 batch 写入(SQLite);
  • 索引优化:为高频查询字段添加索引,加速读取。

四、云服务与扩展

  • 腾讯云 COS + CDN:存储大型文件(如图片、视频),通过 CDN 加速访问;
  • Firebase Firestore:集成云端 NoSQL 数据库,支持离线数据自动同步。

五、调试与监控

  • 缓存命中率监控:通过 Hive.generateSecureKey() 记录缓存使用情况;
  • 性能分析工具:使用 flutter_devtools 检测数据库查询耗时。

总结

响应式缓存数据库的核心在于 数据流与本地存储的无缝结合。对于轻量级场景,推荐 Hive + StreamBuilder;复杂场景可选择 SQLite + RiverpodRealm。开发者需根据数据规模、同步需求和性能要求选择方案,并合理设计缓存策略以避免内存溢出或数据过时。


在 Flutter 中实现 ListView 滚动到不可见数据 的核心在于精准定位目标项的位置并触发滚动动作。以下是综合多篇技术资料的实现方案与优化建议:


一、基础方法:使用 ScrollController 控制滚动

1. 固定高度项滚动

若列表项高度固定(如统一为 50px),可直接通过 ScrollController 计算目标偏移量:

final ScrollController _controller = ScrollController();

// 滚动到第100项(假设每项高度固定为50px)
void _scrollToIndex(int index) {
final double offset = 50.0 * index;
_controller.animateTo(
offset,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);
}

ListView.builder(
controller: _controller,
itemExtent: 50.0, // 声明固定高度以提升性能
itemCount: 1000,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)

适用场景:列表项高度固定且数据量较大的场景。

2. 动态高度项滚动

若列表项高度不固定,需借助 RenderObject 动态计算位置:

void _scrollToDynamicItem(int index) {
final key = GlobalKey();
WidgetsBinding.instance.addPostFrameCallback((_) {
final context = key.currentContext;
if (context != null) {
Scrollable.ensureVisible(
context,
alignment: 0.5, // 滚动至屏幕中间
duration: Duration(seconds: 1),
);
}
});
}

ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) => ListTile(
key: index == targetIndex ? key : null,
title: Text('Item $index'),
),
)

注意:需确保目标项已渲染,否则无法获取 GlobalKey 的上下文。


二、进阶方案:第三方库优化

1. 使用 scroll_to_index 插件

该库支持动态高度计算与精准定位:

final AutoScrollController _autoController = AutoScrollController();

ListView.builder(
controller: _autoController,
itemCount: 1000,
itemBuilder: (context, index) => AutoScrollTag(
key: ValueKey(index),
controller: _autoController,
index: index,
child: ListTile(title: Text('Item $index')),
),
);

// 滚动到目标项
_autoController.scrollToIndex(
targetIndex,
preferPosition: AutoScrollPosition.middle,
);

优势:自动处理动态高度,支持滚动位置微调。

2. 使用 scrollable_positioned_list

专为长列表设计的库,提供高性能滚动控制:

final ItemScrollController _itemController = ItemScrollController();

ScrollablePositionedList.builder(
itemScrollController: _itemController,
itemCount: 1000,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
);

// 直接滚动到索引位置
_itemController.scrollTo(
index: targetIndex,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);

适用场景:需频繁定位或动态高度项较多的场景。


三、性能优化与注意事项

1. 懒加载与渲染优化

  • 预加载范围:通过 cacheExtent 扩大 ListView 的预渲染区域,确保目标项附近数据已加载:
    ListView.builder(
    cacheExtent: 1000.0, // 预加载1屏外的数据
    // ...
    )
  • 异步滚动:在数据加载完成后延迟触发滚动:
    Future.delayed(Duration(milliseconds: 100), () => _scrollToIndex(targetIndex));

2. 避免常见错误

  • GlobalKey 未绑定:确保目标项在 ListView.builder 中正确绑定 GlobalKey
  • 跨页面定位:若目标项在另一页面,需等待页面跳转动画完成后再触发滚动。

3. 动态高度处理策略

  • 预估高度:使用 prototypeItem 提供近似高度以优化计算:
    ListView.builder(
    prototypeItem: ListTile(title: Text('Prototype Item')),
    // ...
    )
  • 高度缓存:对已计算过的高度进行缓存,避免重复计算。

四、方案对比与选型建议

方法适用场景优点缺点
ScrollController固定高度、简单定位无需依赖库,代码简洁动态高度需手动计算
GlobalKey+ensureVisible已知渲染项的精确定位支持任意位置对齐依赖项渲染状态,需异步保证
scroll_to_index动态高度、复杂交互自动计算位置,API丰富需引入第三方库
scrollable_positioned_list超长列表、高性能需求专为长列表优化,流畅度高配置复杂度较高

总结

  • 优先选择第三方库:对动态高度或复杂定位场景,推荐使用 scroll_to_indexscrollable_positioned_list 以简化开发。
  • 性能敏感场景:固定高度列表使用 ScrollController,通过 itemExtent 声明高度提升计算效率。
  • 强制渲染不可见项:结合 cacheExtent 扩大预加载范围,确保目标项已渲染后再触发 Scrollable.ensureVisible

微信公众号

微信公众号

前端开发与设计

· 阅读需 1 分钟
Quany
软件工程师

UI 提的逻辑问题

  • 新增等位成功后需要定位相应的页签展示排队信息, 新增一个排队后,需要定位选中新增的排队
  • 卡片撑满屏高,需从最外层布局开始撑满;
  • 可预订桌台显示不足一屏时,可否用空表格撑满一屏,现在露出下面的灰色底感觉很丑
  • 键盘拉起遮挡输入框的时候,页面需要自动整体上移露出输入框
  • 选中时,桌台图标变小了

微信公众号

微信公众号

NotebookLM

· 阅读需 6 分钟
Quany
软件工程师

NotebookLM 是谷歌开发的一款AI驱动的笔记管理和研究助手工具,旨在帮助用户更高效地组织、分析和利用信息。以下是关于NotebookLM的详细信息:

基本定义

  • NotebookLM是一款基于人工智能的笔记应用程序,它不仅仅是一个简单的笔记记录工具,更像是一个智能的研究助理。
  • 它通过强大的AI功能,将用户的笔记、文档甚至网页转化为一个互动的学习空间,极大地提升了学习效率。

特点

  • 基于Gemini 2.0模型:NotebookLM的核心驱动力是谷歌强大的Gemini 2.0模型,这赋予了它卓越的多模态理解能力,使其能够处理和分析各种类型的信息来源。
  • 多种文件格式支持:用户可以轻松上传文本文件(如PDF、Google文档)、网页内容(直接链接或保存的HTML)、多媒体文件(如YouTube视频、音频文件)和演示文稿(如Google幻灯片)等。
  • 隐私和安全:谷歌明确承诺,不会使用用户的个人数据(包括上传的来源、提出的查询以及模型生成的回答)来训练NotebookLM或任何其他AI模型。用户上传的内容仅用于在用户的NotebookLM实例中提供服务,用户对其数据拥有控制权。

功能

  • 总结信息:NotebookLM能够快速总结上传文档的关键信息,帮助用户快速理解复杂内容。
  • 生成内容:它可以根据用户上传的资料生成学习指南、时间轴、常见问题、摘要、播客等,以多种方式呈现信息。
  • 智能问答:用户可以向NotebookLM提出关于资料的问题,它会基于上传的资料提供准确的回答,并附带引用。
  • 资料发现:通过“Discover”功能,用户只需描述感兴趣的主题,NotebookLM就会自动从网络上收集相关的资料,并创建一个精选的资料列表。

应用场景

  • 高效学习与研究:学生和研究人员可以上传教科书章节、讲座录音、研究论文等,NotebookLM能够帮助解释复杂概念、提供实例、生成学习指南或回答特定问题,显著加速知识内化过程。
  • 内容创作与思路整理:作家、分析师或项目经理可以上传背景资料、访谈记录、市场报告等,NotebookLM可以帮助快速梳理信息、生成演示文稿大纲、提炼关键沟通要点,并附带源材料佐证。
  • 激发创意与洞察发现:产品经理、设计师或市场营销人员可以上传头脑风暴笔记、用户反馈、竞品分析等,NotebookLM能够帮助发现隐藏的趋势、模式或用户需求,生成新的产品创意或营销角度。

隐私和安全

  • 不使用个人数据进行训练:谷歌不会使用用户的个人数据来训练NotebookLM或任何其他AI模型。
  • 用户掌控数据:用户上传的内容仅用于在用户的NotebookLM实例中提供服务,用户对其数据拥有控制权。

总之,NotebookLM通过整合强大的Gemini 2.0多模态能力、提供基于来源的可信回答、创新的音频功能以及对用户隐私的坚定承诺,将自己定位为一个不可或缺的个性化AI研究助理。它不仅仅帮助用户“记笔记”,更是赋能用户从信息中“提炼智慧”。对于任何需要深度处理和理解复杂信息的人来说,NotebookLM都值得尝试。


好的!以下是关于 Flutter 中 CompositedTransformTargetCompositedTransformFollower 的中文详解:


什么是 CompositedTransformTargetCompositedTransformFollower

它们是 Flutter 中一对协同工作的组件,用于动态定位一个部件(跟随者)相对于另一个部件(目标)的位置,即使目标在动画或布局变化中移动,跟随者也能实时更新位置。
这对组件通过共享 LayerLink 对象来建立关联,常用于实现工具提示(Tooltip)、悬浮菜单、动态吸附效果等。


核心概念

  1. LayerLink

    • 一个共享的“链接对象”,用于传递目标部件的位置信息。
    • 需要同时传给 CompositedTransformTargetCompositedTransformFollower
  2. CompositedTransformTarget

    • 包裹需要被跟踪的“目标部件”(如按钮)。
    • 将目标的位置信息写入 LayerLink
  3. CompositedTransformFollower

    • 包裹需要跟随目标的“跟随部件”(如提示框)。
    • LayerLink 读取目标位置,并根据 offset 调整自身位置。

典型使用场景

  • 按钮的浮动提示框(Tooltip)。
  • 下拉菜单跟随输入框。
  • 动态吸附的动画效果(如按钮展开的菜单)。

代码示例:按钮的跟随提示框

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: FollowTooltipDemo(),
),
),
);
}
}

class FollowTooltipDemo extends StatefulWidget {

_FollowTooltipDemoState createState() => _FollowTooltipDemoState();
}

class _FollowTooltipDemoState extends State<FollowTooltipDemo> {
final LayerLink _layerLink = LayerLink(); // 共享的链接对象
OverlayEntry? _overlayEntry; // 用于显示跟随部件的覆盖层

// 显示提示框
void _showTooltip() {
_overlayEntry = OverlayEntry(
builder: (context) => CompositedTransformFollower(
link: _layerLink,
offset: const Offset(0, 48), // 提示框在目标下方 48 像素处
child: Material(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text('这是一个跟随按钮的提示框!'),
),
),
),
);
Overlay.of(context)?.insert(_overlayEntry!);
}

// 隐藏提示框
void _hideTooltip() {
_overlayEntry?.remove();
_overlayEntry = null;
}


Widget build(BuildContext context) {
return CompositedTransformTarget(
link: _layerLink, // 关联目标部件
child: ElevatedButton(
onPressed: _showTooltip,
onLongPressEnd: (details) => _hideTooltip(), // 长按结束隐藏
child: const Text('点击我'),
),
);
}


void dispose() {
_hideTooltip(); // 清理覆盖层
super.dispose();
}
}

关键解释

  1. OverlayEntry

    • 通过覆盖层(Overlay)显示跟随部件,确保其悬浮在其他内容之上。
    • 必须手动管理覆盖层的插入(insert)和移除(remove)。
  2. offset

    • 控制跟随部件相对于目标的位置偏移,例如 Offset(0, 48) 表示向下偏移 48 像素。
  3. 生命周期管理

    • dispose() 中清理覆盖层,避免内存泄漏。

注意事项

  • 性能优化:这对组件直接操作 Flutter 的合成层(compositing layer),适合动态场景,但避免过度使用。
  • 复杂布局:若需要更复杂的定位逻辑,可通过 offset 动态计算位置(如根据屏幕边缘自动调整)。
  • 交互协调:示例中使用长按触发提示框,实际可根据需求改用 onHover 或手势控制。

通过这对组件,你可以轻松实现部件间的动态跟随效果,让 UI 更具交互性!

微信公众号

微信公众号

TeamViewer

· 阅读需 3 分钟
Quany
软件工程师

以下是 Flutter 中 Flex 布局(Row/Column) 的深度解析与实用示例,涵盖核心概念、常见场景和代码实践:


1. Flex 布局核心概念

概念说明
主轴 (Main Axis)Row 的水平方向 / Column 的垂直方向(由 mainAxisAlignment 控制子项排列)
交叉轴 (Cross Axis)与主轴垂直的方向(由 crossAxisAlignment 控制对齐)
Expanded占据剩余空间的弹性子项(需指定 flex 权重)
Flexible类似 Expanded,但允许子项不填满可用空间
Spacer占用空白区域的灵活组件(基于 flex 值)

2. 基础用法示例

(1) Row 水平布局

Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // 主轴对齐方式
crossAxisAlignment: CrossAxisAlignment.center, // 交叉轴对齐方式
children: [
Container(width: 50, height: 50, color: Colors.red),
Container(width: 50, height: 50, color: Colors.green),
Container(width: 50, height: 50, color: Colors.blue),
],
)

(2) Column 垂直布局

Column(
mainAxisSize: MainAxisSize.min, // 主轴尺寸最小化
children: [
Text('Header'),
Divider(),
Expanded( // 占据剩余空间
child: ListView(children: [/* ... */]),
),
],
)

3. 弹性空间分配 (Expanded/Flexible)

(1) 按比例分配空间

Row(
children: [
Expanded(
flex: 2, // 权重为2,占2/(2+1) = 66.6%
child: Container(height: 50, color: Colors.red),
),
Expanded(
flex: 1, // 权重为1,占1/(2+1) = 33.3%
child: Container(height: 50, color: Colors.blue),
),
],
)

(2) Flexible 的灵活空间

Row(
children: [
Flexible(
fit: FlexFit.loose, // 允许子项小于可用空间
child: Container(
width: 100, // 最大宽度100,不足时按实际内容调整
color: Colors.yellow,
),
),
Expanded( // 强制填满剩余空间
child: Container(height: 50, color: Colors.green),
),
],
)

4. 高级布局技巧

(1) 使用 Spacer 填充空白

Row(
children: [
Container(width: 50, height: 50, color: Colors.red),
Spacer(flex: 1), // 占据剩余空间
Container(width: 50, height: 50, color: Colors.blue),
],
)

(2) 嵌套布局 (Row + Column)

Column(
children: [
Row(
children: [
Icon(Icons.star),
SizedBox(width: 8),
Expanded(
child: Text('Flutter Flex Layout Guide'),
),
],
),
Divider(),
Expanded(
child: Row(
children: [
Expanded(flex: 1, child: Sidebar()),
VerticalDivider(),
Expanded(flex: 3, child: ContentArea()),
],
),
),
],
)

5. 常见问题与解决方案

(1) 内容溢出 (Overflow)

当子项总宽度超过主轴空间时,使用 ListViewSingleChildScrollView 包裹:

SingleChildScrollView(
scrollDirection: Axis.horizontal, // 水平滚动
child: Row(children: [/* 多个宽子项 */]),
)

(2) 动态调整布局

结合 MediaQuery 实现响应式布局:

Row(
children: [
if (MediaQuery.of(context).size.width > 600) // 大屏显示侧边栏
Expanded(flex: 1, child: Sidebar()),
Expanded(flex: 3, child: MainContent()),
],
)

6. 布局调试工具

  • Flutter Inspector:实时查看布局结构
  • Debug Painting:添加调试边框
    MaterialApp(
    debugShowCheckedModeBanner: false,
    debugShowMaterialGrid: true, // 显示网格
    );

7. 性能优化

  • 避免在 Row/Column 中使用大量子项(超过20个时,优先考虑 ListViewGridView
  • 对复杂子项使用 const 构造函数减少重建:
    Row(
    children: const [
    Icon(Icons.access_alarm),
    SizedBox(width: 10),
    Text('Static Content'),
    ],
    )

通过以上方法,你可以高效利用 Flutter 的 Flex 布局构建自适应 UI。遇到具体问题时,可结合 FlexibleExpanded 动态调整空间分配。

微信公众号

微信公众号

Flutter ClipRRect

· 阅读需 9 分钟
Quany
软件工程师

1. 基础用法

ClipRRect 包裹子组件,并通过 borderRadius 设置圆角:

ClipRRect(
borderRadius: BorderRadius.circular(20), // 统一圆角半径
child: Image.network('https://example.com/image.jpg'),
)

2. 自定义不同圆角

BorderRadius.only 为特定角设置不同半径:

ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30), // 左上角30
bottomRight: Radius.circular(15), // 右下角15
),
child: Container(
color: Colors.blue,
width: 200,
height: 200,
),
)

3. 裁剪图片为圆角

常见场景(如头像、卡片):

ClipRRect(
borderRadius: BorderRadius.circular(100), // 圆形效果(半径=宽度/2)
child: Image.network(
'https://picsum.photos/200',
width: 200,
height: 200,
fit: BoxFit.cover,
),
)

4. 与其他组件结合

例如裁剪 ListView 的滚动区域:

Container(
height: 300,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: ListView(
children: [ /* 列表项 */ ],
),
),
)

5. 添加边框

ClipRRect 的子组件中使用带圆角的 Container

ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15), // 圆角与 ClipRRect 一致
border: Border.all(color: Colors.grey, width: 2),
),
child: Image.network('https://example.com/image.jpg'),
),
)

6. 动态圆角动画

使用 AnimatedContainer 实现圆角动画:

double _radius = 10;

AnimatedContainer(
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_radius),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: YourChildWidget(), // 你的子组件
),
)
// 修改 _radius 的值触发动画

关键注意事项

  • 适用场景:裁剪图片、容器等为圆角(尤其当子组件本身不支持圆角时)。
  • 性能优化:优先用 ClipRRect 而非 ClipPath(圆角矩形场景下更高效)。
  • 边框问题:若需要边框,需同时设置 ClipRRect 和子容器的圆角。

完整代码示例

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('ClipRRect 示例')),
body: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(40), // 圆角半径40
child: Image.network(
'https://picsum.photos/250?image=9',
width: 250,
height: 250,
fit: BoxFit.cover,
),
),
),
),
);
}
}

效果:显示一个带有圆角(半径40)的图片。可根据需求调整参数。


在 Flutter 中,虽然官方没有内置类似 React Hooks 的机制,但社区提供了多种方案来实现类似的功能。以下是 Flutter 中主流的 React Hooks 风格解决方案及其核心特点:


1. flutter_hooks

最接近 React Hooks 的解决方案,由 Rémi Rousselet(Provider 作者)开发,支持状态管理、副作用处理等。

核心特性

  • 内置常用 Hooks:如 useState, useEffect, useMemo, useContext, useAnimationController 等。
  • 自定义 Hooks:可封装复杂逻辑为可复用的 Hook。
  • 轻量级:减少 StatefulWidget 的模板代码。
  • 与 Riverpod 集成:结合 Riverpod 状态管理更高效。

示例代码

import 'package:flutter_hooks/flutter_hooks.dart';

class CounterExample extends HookWidget {

Widget build(BuildContext context) {
final counter = useState(0);
useEffect(() {
print('Counter changed: ${counter.value}');
return () => print('Cleanup');
}, [counter.value]);

return Text('Count: ${counter.value}');
}
}

常用 Hooks

  • useState: 管理简单状态。
  • useEffect: 处理副作用(类似 componentDidMount/componentDidUpdate)。
  • useMemo: 缓存计算结果。
  • useAnimationController: 简化动画控制。
  • useTextEditingController: 管理输入框控制器。

2. Riverpod + Hooks

Riverpod 是 Provider 的升级版,天然支持与 flutter_hooks 结合,提供更灵活的状态管理。

核心特性

  • 响应式状态管理:自动依赖追踪。
  • 类型安全:避免 Provider 的上下文依赖问题。
  • 支持 HookWidget:通过 HookConsumerWidgetuseProvider 直接访问状态。

示例代码

import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final counterProvider = StateProvider<int>((ref) => 0);

class RiverpodHooksExample extends HookConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
final controller = useTextEditingController();

return Column(
children: [
Text('Count: $counter'),
TextField(controller: controller),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('Increment'),
),
],
);
}
}

3. Hooks 风格的 BLoC(通过 flutter_bloc

虽然 flutter_bloc 主要基于传统的 Cubit/Bloc 模式,但可以通过扩展实现类似 Hooks 的简洁性。

示例代码

import 'package:flutter_bloc/flutter_bloc.dart';

class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
}

class BlocHooksExample extends StatelessWidget {

Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CounterCubit(),
child: Builder(
builder: (context) {
final counter = context.watch<CounterCubit>().state;
return Text('Count: $counter');
},
),
);
}
}

4. 原生 StatefulWidget 的简化写法

如果不想依赖第三方库,可以通过 Dart 的 函数式编程特性 简化状态管理:

示例代码

class NativeCounter extends StatefulWidget {

_NativeCounterState createState() => _NativeCounterState();
}

class _NativeCounterState extends State<NativeCounter> {
int _counter = 0;


Widget build(BuildContext context) {
return Text('Count: $_counter');
}
}

对比与选择

方案优点缺点适用场景
flutter_hooks最接近 React Hooks,功能全面需要学习新库复杂状态/副作用管理
Riverpod + Hooks类型安全,依赖清晰,与 Hooks 深度集成需同时理解 Riverpod 和 Hooks大型项目,强类型需求
BLoC明确的状态管理分层模板代码较多需要严格状态分离的项目
原生 StatefulWidget无依赖,官方支持代码冗余,无法复用逻辑简单组件或小型项目

推荐组合

  1. 推荐组合flutter_hooks + Riverpod
    适合大多数项目,提供简洁的状态管理和副作用处理。
  2. 轻量级选择:仅 flutter_hooks
    适合中小型项目,快速减少模板代码。
  3. 企业级架构BLoC + 自定义 Hooks
    适合需要严格架构分层的团队。

通过合理选择方案,可以在 Flutter 中实现类似 React Hooks 的开发体验,提升代码可读性和维护性!


在 Flutter 中,Riverpod + Hooks 是一种强大的组合,结合了 状态管理(Riverpod)Hooks 风格的副作用管理(flutter_hooks,能够显著简化代码并提升开发效率。以下是详细指南:


1. 核心优势

  • 类型安全:Riverpod 2.0+ 提供完全类型安全的依赖管理。
  • 无上下文依赖:无需依赖 BuildContext 访问状态。
  • Hooks 集成:通过 HookConsumerWidgetuseProvider 直接访问状态。
  • 副作用简化:利用 Hooks 管理动画、控制器、订阅等。

2. 安装依赖

pubspec.yaml 中添加:

dependencies:
flutter_riverpod: ^2.0.0
flutter_hooks: ^0.20.0
hooks_riverpod: ^2.0.0 # Riverpod 与 Hooks 的桥接库

运行 flutter pub get


3. 基本用法

步骤 1:定义 Provider

// 定义一个计数器状态 Provider
final counterProvider = StateProvider<int>((ref) => 0);

// 定义异步数据 Provider(如 API 请求)
final userDataProvider = FutureProvider<User>((ref) async {
final response = await http.get(Uri.parse('https://api.example.com/user'));
return User.fromJson(response.body);
});

步骤 2:在组件中使用状态

使用 HookConsumerWidget 结合 Hooks 和 Riverpod:

class CounterExample extends HookConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
// 使用 Hook 管理本地状态
final localCounter = useState(0);

// 读取 Riverpod 状态
final counter = ref.watch(counterProvider);
final userAsync = ref.watch(userDataProvider);

return Column(
children: [
Text('Global Counter: $counter'),
Text('Local Counter: ${localCounter.value}'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('Increment Global'),
),
ElevatedButton(
onPressed: () => localCounter.value++,
child: Text('Increment Local'),
),
// 处理异步状态
userAsync.when(
data: (user) => Text('User: ${user.name}'),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
),
],
);
}
}

4. 常用 Hooks 与 Riverpod 结合

useProvider 直接访问状态

final counter = useProvider(counterProvider);

useState + Riverpod 状态更新

final counter = useState(0);
final apiData = useProvider(apiProvider);

useEffect(() {
if (apiData.isLoaded) {
counter.value = apiData.value!.count;
}
}, [apiData]);

useAnimationController 与状态联动

class AnimatedButton extends HookConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
final isActive = ref.watch(buttonActiveProvider);
final controller = useAnimationController(
duration: Duration(milliseconds: 300),
);

useEffect(() {
if (isActive) {
controller.forward();
} else {
controller.reverse();
}
return null;
}, [isActive]);

return ScaleTransition(
scale: CurvedAnimation(parent: controller, curve: Curves.easeInOut),
child: ElevatedButton(...),
);
}
}

5. 自定义 Hooks 与 Riverpod

封装复用逻辑(如主题切换):

// 自定义 Hook:监听主题模式
AutoDisposeStateNotifierProvider<ThemeNotifier, bool> themeProvider =
StateNotifierProvider.autoDispose((ref) => ThemeNotifier());

class ThemeNotifier extends StateNotifier<bool> {
ThemeNotifier() : super(false);
void toggle() => state = !state;
}

// 使用自定义 Hook
bool useTheme() {
final isDarkMode = useProvider(themeProvider);
final notifier = useProvider(themeProvider.notifier);
return isDarkMode;
}

// 在组件中使用
class ThemeSwitcher extends HookConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
final isDarkMode = useTheme();
return Switch(
value: isDarkMode,
onChanged: (value) => ref.read(themeProvider.notifier).toggle(),
);
}
}

6. 异步操作与错误处理

结合 useAsyncValueAsyncValue 处理加载和错误:

final userProvider = FutureProvider<User>((ref) => fetchUser());

class UserProfile extends HookConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userProvider);

return userAsync.when(
data: (user) => Text(user.name),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Error: $e'),
);
}
}

7. 性能优化

  • 选择性刷新:使用 select 监听状态的特定部分:
    final userName = ref.watch(userProvider.select((user) => user.name));
  • 自动销毁:使用 autoDispose 避免内存泄漏:
    final tempProvider = StateProvider.autoDispose<int>((ref) => 0);

8. 完整示例:Todo App

// Provider 定义
final todoListProvider = StateNotifierProvider.autoDispose<TodoListNotifier, List<Todo>>(
(ref) => TodoListNotifier(),
);

class TodoListNotifier extends StateNotifier<List<Todo>> {
TodoListNotifier() : super([]);
void addTodo(String text) => state = [...state, Todo(text: text)];
}

// 组件
class TodoScreen extends HookConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
final todoList = ref.watch(todoListProvider);
final controller = useTextEditingController();

return Column(
children: [
TextField(controller: controller),
ElevatedButton(
onPressed: () => ref.read(todoListProvider.notifier).addTodo(controller.text),
child: Text('Add Todo'),
),
ListView.builder(
itemCount: todoList.length,
itemBuilder: (_, index) => ListTile(title: Text(todoList[index].text)),
),
],
);
}
}

9. 注意事项

  1. 依赖顺序:Hooks 必须在组件的 build 方法顶部调用,不可嵌套在条件语句中。
  2. 状态分离:将全局状态(Riverpod)和局部状态(Hooks)合理区分。
  3. 清理资源:使用 autoDisposeuseEffect 的清理函数避免内存泄漏。
  4. 调试工具:使用 Riverpod 的 官方调试工具 优化代码。

10. 与纯 flutter_hooks 对比

场景Riverpod + Hooksflutter_hooks
全局状态管理✅ 更简洁,类型安全❌ 需手动结合其他库(如 Provider)
组件间共享状态✅ 天然支持❌ 依赖上下文传递
异步操作✅ 内置 AsyncValue 处理❌ 需手动管理
代码复用✅ 通过 Provider + Hooks 高度封装✅ 仅通过 Hooks 封装

总结

Riverpod + Hooks 是 Flutter 开发现代化的最佳实践之一,尤其适合以下场景:

  • 需要类型安全的状态管理。
  • 组件涉及复杂的副作用(动画、订阅等)。
  • 项目规模较大,需严格分离业务逻辑和 UI。

通过合理利用两者的优势,可以显著提升代码的可维护性和开发效率!

微信公众号

微信公众号