【Flutter 工程】005-代码分离实践:flutter_hooks & functional_widget
文章目录
- 【Flutter 工程】005-代码分离实践:flutter_hooks & functional_widget
- 一、概述
- 1、Flutter “嵌套地狱”
- 2、代码分离实践
- 二、实践
- 1、安装 flutter_hooks & functional_widget
- 2、代码示例
- 3、生成代码
- 命令
- 生成的代码
- 4、运行结果
一、概述
1、Flutter “嵌套地狱”
在Flutter开发中,“嵌套地狱”(Nesting Hell)是指在构建复杂的UI布局时,由于多层嵌套的组件结构,代码变得冗长、难以维护和理解的情况。
Flutter使用组件树的方式来构建用户界面,每个UI元素都是一个组件,可以包含其他组件。在某些情况下,特别是当需要实现复杂的布局或嵌套的组件结构时,代码中的组件嵌套层级可能会不断增加,从而导致出现"嵌套地狱"。
"嵌套地狱"可能会带来以下问题:
- 代码冗长和可读性差:过多的嵌套会导致代码变得冗长,难以理解和维护。每个嵌套层级都需要处理相应的组件和属性,使得代码结构复杂化。
- 性能问题:过多的嵌套可能会导致渲染性能下降。每个嵌套层级都需要进行布局计算和绘制操作,增加了渲染的负担。
- 调试和排查问题困难:当出现UI问题或错误时,由于嵌套层级较多,定位问题可能会变得更加困难。调试和排查错误所需的时间和精力也会增加。
为了避免"嵌套地狱",可以考虑以下策略:
- 抽取可复用的组件:将复杂的UI部分拆分为独立的可复用组件,使代码更加模块化和清晰。这样可以减少嵌套层级,并使代码更易读和维护。
- 使用布局组件:Flutter提供了各种布局组件(如Row、Column、Stack等),可以帮助管理UI布局。合理使用这些布局组件可以减少嵌套层级,并简化布局代码。
- 使用状态管理工具:对于具有复杂交互和状态管理的应用,使用适当的状态管理工具(如Provider、Bloc等)可以减少嵌套层级,并更好地组织和管理应用的状态和逻辑。
- 审视UI设计和交互需求:在设计UI和交互时,尽量避免过于复杂和深层次的嵌套结构,简化UI布局和交互流程,以提高代码的可读性和维护性。
2、代码分离实践
结合 flutter_hooks & functional_widget 两个库实现代码分离。
参考文章:
【Flutter 工程】003-钩子函数:Flutter Hooks
https://blog.csdn.net/qq_29689343/article/details/130885106
【Flutter 工程】004-代码生成:functional_widget
https://blog.csdn.net/qq_29689343/article/details/130887815
用一种更有条理的方法写Flutter代码——使用Flutter Hooks与函数式组件
https://blog.csdn.net/qq_50101967/article/details/128688448
二、实践
1、安装 flutter_hooks & functional_widget
# 安装 flutter_hooks
flutter pub add flutter_hooks
# 安装 functional_widget
flutter pub add dev:functional_widget dev:build_runner functional_widget_annotation
2、代码示例
方法是否以
$
开头有自己决定!
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
part 'main.g.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
/// 视图代码
class MyHomePage extends HookWidget {
const MyHomePage({super.key, required this.title});
final String title;
Widget build(BuildContext context) {
final counter = Counter.use(0);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const $OnlyText('You have pushed the button this many times:'),
$TextWithStyle('${counter.value}'),
$AddButton(counter.inc),
$DecButton(counter.dec),
],
),
),
);
}
}
/// 逻辑代码
class Counter {
static use(initialValue) {
return Counter().._count = useState(initialValue);
}
late final ValueNotifier<int> _count;
get value => _count.value;
inc() {
_count.value++;
}
dec() {
_count.value--;
}
}
/// 样式代码
Widget $onlyText(String text) {
return Text(text);
}
Widget $textWithStyle(BuildContext context, String text) {
return Text(
text,
style: Theme.of(context).textTheme.headlineLarge,
);
}
Widget $addButton(final VoidCallback? onPressed) {
return FloatingActionButton(
onPressed: onPressed,
tooltip: 'Increment',
child: const Icon(Icons.add),
);
}
Widget $decButton(final VoidCallback? onPressed) {
return FloatingActionButton(
onPressed: onPressed,
tooltip: 'Decrement',
child: const Icon(Icons.minimize),
);
}
3、生成代码
命令
# --delete-conflicting-outputs 可选,会在生成代码冲突的时候,删除原来的代码,重新生成
flutter pub run build_runner build --delete-conflicting-outputs
生成的代码
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'main.dart';
// **************************************************************************
// FunctionalWidgetGenerator
// **************************************************************************
/// 样式代码
class $OnlyText extends StatelessWidget {
/// 样式代码
const $OnlyText(
this.text, {
Key? key,
}) : super(key: key);
/// 样式代码
final String text;
Widget build(BuildContext _context) => $onlyText(text);
}
class $TextWithStyle extends StatelessWidget {
const $TextWithStyle(
this.text, {
Key? key,
}) : super(key: key);
final String text;
Widget build(BuildContext _context) => $textWithStyle(
_context,
text,
);
}
class $AddButton extends StatelessWidget {
const $AddButton(
this.onPressed, {
Key? key,
}) : super(key: key);
final void Function()? onPressed;
Widget build(BuildContext _context) => $addButton(onPressed);
}
class $DecButton extends StatelessWidget {
const $DecButton(
this.onPressed, {
Key? key,
}) : super(key: key);
final void Function()? onPressed;
Widget build(BuildContext _context) => $decButton(onPressed);
}