当InkerWell组件内部获取到焦点时,会展示一层灰色遮罩
将focusColor属性设置为透明即可
Flutter InkWell焦点效果源码分析
问题描述
当 InkWell 组件获得焦点时,会显示一层灰色遮罩效果。需要找出这个效果是由哪些组件控制的,以及具体的实现机制。
排查思路
1. 从InkWell组件入手
首先查看 InkWell 类的定义:
dart
class InkWell extends InkResponse {
const InkWell({
Key? key,
Widget? child,
Color? focusColor,
// ...更多属性
})
发现:
- InkWell 继承自 InkResponse
- 有 focusColor 属性可以控制焦点颜色
2. 追踪InkResponse实现
在 InkResponse 中找到焦点相关的重要方法:
dart
void handleFocusUpdate(bool hasFocus) {
_hasFocus = hasFocus;
statesController.update(MaterialState.focused, hasFocus);
updateFocusHighlights();
widget.onFocusChange?.call(hasFocus);
}
关键发现:
- 焦点状态变化时会调用 updateFocusHighlights()
- 使用 statesController 管理状态
3. 分析高亮实现
找到 updateHighlight 方法:
dart
void updateHighlight(_HighlightType type, { required bool value }) {
final InkHighlight? highlight = _highlights[type];
if (value) {
if (highlight == null) {
_highlights[type] = InkHighlight(
controller: Material.of(context)!,
referenceBox: referenceBox,
color: getHighlightColorForType(type),
shape: widget.highlightShape,
// ...
);
}
}
}
重要发现:
- 使用 InkHighlight 类来实现高亮效果
- 高亮效果存储在 _highlights Map 中
- 通过 Material.of(context) 获取控制器
4. 追踪颜色获取逻辑
在 getHighlightColorForType 方法中:
dart
Color getHighlightColorForType(_HighlightType type) {
final ThemeData theme = Theme.of(context);
switch (type) {
case _HighlightType.focus:
return widget.focusColor ?? theme.focusColor;
// ...
}
}
了解到:
- 焦点颜色优先使用 widget.focusColor
- 如果未指定则使用主题中的 focusColor
5. 分析Material实现
Material 组件的作用:
- 创建 _RenderInkFeatures 来管理 ink 效果
- 提供 MaterialInkController 接口
- 处理实际的绘制逻辑
dart
class _RenderInkFeatures extends RenderProxyBox implements MaterialInkController {
void addInkFeature(InkFeature feature) {
_inkFeatures ??= <InkFeature>[];
_inkFeatures!.add(feature);
markNeedsPaint();
}
void paint(PaintingContext context, Offset offset) {
if (_inkFeatures != null && _inkFeatures!.isNotEmpty) {
final Canvas canvas = context.canvas;
// 绘制所有ink特效
for (final InkFeature inkFeature in _inkFeatures!) {
inkFeature._paint(canvas);
}
}
}
}
实现流程总结
-
触发焦点:
- Focus widget 检测到焦点变化
- 调用 handleFocusUpdate
-
创建高亮:
- updateFocusHighlights 判断是否需要显示焦点
- updateHighlight 创建 InkHighlight 实例
-
设置颜色:
- getHighlightColorForType 获取焦点颜色
- 优先使用 focusColor 属性,否则使用主题颜色
-
渲染过程:
- InkHighlight 被添加到 Material 的 _inkFeatures
- _RenderInkFeatures 在绘制时遍历所有特效
- 通过 Canvas API 实现最终的视觉效果
修改建议
如果需要自定义焦点效果,可以:
- 设置 InkWell 的 focusColor 属性
- 在 ThemeData 中配置全局 focusColor
- 使用 MaterialState 配置更复杂的状态样式
相关类和文件
- InkWell
- InkResponse
- InkHighlight
- Material
- MaterialInkController
- _RenderInkFeatures
参考
- Flutter SDK Material 源码
- Flutter 文档中的 InkWell 部分