0%

Flutter禁用水波纹

在做Flutter开发的时候,通常我们都使用MaterialApp来开发,最典型的样式就是点击会有水波纹效果,但有时候我们不希望有水波纹效果,例如在iOS上,使用TextFiled的时候禁用水波纹效果,让体验看起来更像原生

搜索了一番,没有特别好的方法,基本上是修改splashColor,感觉不够彻底,于是从源码入手看下,我们知道水波纹效果的Widget为InkWell

1
2
3
4
InkWell(
onTap: () {},
child: Text("button")
)

InkWell继承自InkResponse,在_InkResponseState中的方法_handleTapDown可以看到,在点击的时候会开启splash

1
2
3
4
5
6
void _handleTapDown(TapDownDetails details) {
_startSplash(details: details);
if (widget.onTapDown != null) {
widget.onTapDown(details);
}
}

_startSplash创建了InteractiveInkFeature对象splash

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
void _startSplash({TapDownDetails details, BuildContext context}) {
assert(details != null || context != null);

Offset globalPosition;
if (context != null) {
final RenderBox referenceBox = context.findRenderObject() as RenderBox;
assert(referenceBox.hasSize, 'InkResponse must be done with layout before starting a splash.');
globalPosition = referenceBox.localToGlobal(referenceBox.paintBounds.center);
} else {
globalPosition = details.globalPosition;
}
final InteractiveInkFeature splash = _createInkFeature(globalPosition);
_splashes ??= HashSet<InteractiveInkFeature>();
_splashes.add(splash);
_currentSplash = splash;
updateKeepAlive();
updateHighlight(_HighlightType.pressed, value: true);
}

InteractiveInkFeature _createInkFeature(Offset globalPosition) {
final MaterialInkController inkController = Material.of(context);
final RenderBox referenceBox = context.findRenderObject() as RenderBox;
final Offset position = referenceBox.globalToLocal(globalPosition);
final Color color = widget.splashColor ?? Theme.of(context).splashColor;
final RectCallback rectCallback = widget.containedInkWell ? widget.getRectCallback(referenceBox) : null;
final BorderRadius borderRadius = widget.borderRadius;
final ShapeBorder customBorder = widget.customBorder;

InteractiveInkFeature splash;
void onRemoved() {
if (_splashes != null) {
assert(_splashes.contains(splash));
_splashes.remove(splash);
if (_currentSplash == splash)
_currentSplash = null;
updateKeepAlive();
} // else we're probably in deactivate()
}

splash = (widget.splashFactory ?? Theme.of(context).splashFactory).create(
controller: inkController,
referenceBox: referenceBox,
position: position,
color: color,
containedInkWell: widget.containedInkWell,
rectCallback: rectCallback,
radius: widget.radius,
borderRadius: borderRadius,
customBorder: customBorder,
onRemoved: onRemoved,
textDirection: Directionality.of(context),
);

return splash;
}

该类为抽象类,看名字像是水波纹的实现,主要逻辑就在这里面,InkResponse通过自身属性或从主题中取到Theme.of(context).splashFactory,然后创建InteractiveInkFeature,我们把主题中的factory换成自己实现一个没有水波纹的InteractiveInkFeature对象,就可以间接的关闭掉水波纹的效果了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'package:flutter/material.dart';


// 空水纹实现工厂
class NoSplashFactory extends InteractiveInkFeatureFactory {
@override
InteractiveInkFeature create({MaterialInkController controller, RenderBox referenceBox, Offset position, Color color, TextDirection textDirection, bool containedInkWell = false, rectCallback, BorderRadius borderRadius, ShapeBorder customBorder, double radius, onRemoved}) {
return _NoInteractiveInkFeature(controller: controller, referenceBox: referenceBox);
}
}

// InkFeature空实现
class _NoInteractiveInkFeature extends InteractiveInkFeature {
_NoInteractiveInkFeature({
@required MaterialInkController controller,
@required RenderBox referenceBox,
}) : super(controller: controller, referenceBox: referenceBox);

@override
void paintFeature(Canvas canvas, Matrix4 transform) {}
}

把widget包到Theme

1
2
3
4
5
6
7
8
9
Theme(
data: ThemeData(
splashFactory: Shares.noInkFeatureFactory
),
child: FlatButton(
child: Text("点击了"),
onPressed: () {},
),
)

默认还有点击背景,如果需要把点击的背景也去掉,highlightedColor设置为透明即可

1
2
3
4
ThemeData(
splashFactory: Shares.noInkFeatureFactory,
highlightColor: Colors.transparent,
)

放到NavigationBottomTabBar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Scaffold(
bottomNavigationBar: Theme(
data: ThemeData(
// 去掉水波纹效果
splashFactory: Shares.noInkFeatureFactory,
// 去掉点击效果
highlightColor: Colors.transparent,
),
child: BottomNavigationBar(
...
)
)
...
)