根据TextEditingController实现原理定制响应式控制的Widget

Overview

最近在适配iPad和安卓大屏时,发现项目中有个页面在滚动时频繁build,codeReview代码发现是该页面需要监听页面滚动更改顶部tabbar的颜色。

而在每次滚动的时候都会调用setState(() {});,导致整个页面频繁刷新。

于是根据TextEditingController实现原理定制响应式控制的Widget来解决该问题,记录一下。

同时让AI生成了示例,便于理解,示例也在文档中。

TextEditingController 实现原理

TextEditingController 是 Flutter 中用于控制文本输入框内容的类,其核心原理如下:

  1. ValueNotifier 基础:继承自 ValueNotifier<TextEditingValue>,这意味着它是一个可观察的值,当值变化时会通知所有监听器。

  2. 文本状态管理:维护一个 TextEditingValue 对象,包含:

    • text:当前文本内容
    • selection:文本选择范围
    • composing:输入法组合文本范围
  3. 双向绑定

    • 当用户在 TextField 中输入时,会更新 controller 的值
    • 当通过代码修改 controller 的值时,会同步更新 TextField 显示
  4. 监听机制:通过 addListener 可以注册回调,当文本变化时执行相应操作

实现根据 alpha 参数显隐的 Widget

我们可以仿照 TextField 的实现原理,创建一个基于 ValueNotifier 的可观察 Widget:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import 'package:flutter/material.dart';

class AlphaController extends ValueNotifier<double> {
AlphaController({double alpha = 1.0}) : super(alpha.clamp(0.0, 1.0));

double get alpha => value;

set alpha(double newAlpha) {
value = newAlpha.clamp(0.0, 1.0);
}
}

class AlphaControlledWidget extends StatefulWidget {
final AlphaController controller;
final Widget child;

const AlphaControlledWidget({
Key? key,
required this.controller,
required this.child,
}) : super(key: key);

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

class _AlphaControlledWidgetState extends State<AlphaControlledWidget> {
@override
void initState() {
super.initState();
widget.controller.addListener(_handleAlphaChange);
}

@override
void didUpdateWidget(AlphaControlledWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_handleAlphaChange);
widget.controller.addListener(_handleAlphaChange);
}
}

@override
void dispose() {
widget.controller.removeListener(_handleAlphaChange);
super.dispose();
}

void _handleAlphaChange() {
setState(() {});
}

@override
Widget build(BuildContext context) {
return Opacity(
opacity: widget.controller.alpha,
child: widget.child,
);
}
}

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class AlphaDemo extends StatefulWidget {
@override
_AlphaDemoState createState() => _AlphaDemoState();
}

class _AlphaDemoState extends State<AlphaDemo> {
final AlphaController _controller = AlphaController(alpha: 0.5);

@override
Widget build(BuildContext context) {
return Column(
children: [
Slider(
value: _controller.alpha,
onChanged: (value) {
_controller.alpha = value;
},
),
AlphaControlledWidget(
controller: _controller,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Center(
child: Text(
'透明度控制',
style: TextStyle(color: Colors.white, fontSize: 24),
),
),
),
),
],
);
}
}

实现原理分析

  1. AlphaController:类似于 TextEditingController,继承自 ValueNotifier,负责管理 alpha 值
  2. AlphaControlledWidget:类似于 TextField,监听 controller 的变化并更新 UI
  3. 响应式更新:当 controller 的值变化时,通过 setState 触发 Widget 重建
  4. 生命周期管理:正确处理了 controller 的监听器添加和移除

这种模式可以扩展到其他需要响应式控制的 Widget 属性,如大小、位置、颜色等。