-
Notifications
You must be signed in to change notification settings - Fork 5
/
touch_indicator.dart
115 lines (100 loc) · 3.21 KB
/
touch_indicator.dart
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
library touch_indicator;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
/// Adds touch indicators to the screen whenever a touch occurs
///
/// This can be useful when recording videos of an app where you want to show
/// where the user has tapped. Can also be useful when running integration
/// tests or when giving demos with a screencast.
class TouchIndicator extends StatefulWidget {
/// The child on which to show indicators
final Widget child;
/// The size of the indicator
final double indicatorSize;
/// The color of the indicator
final Color indicatorColor;
/// Overrides the default indicator.
///
/// Make sure to set the proper [indicatorSize] to align the widget properly
final Widget? indicator;
/// If set to true, shows indicators in release mode as well
final bool forceInReleaseMode;
/// If set to false, disables the indicators from showing
final bool enabled;
/// Creates a touch indicator canvas
///
/// Touch indicators are shown on the child whenever a touch occurs
const TouchIndicator({
Key? key,
required this.child,
this.indicator,
this.indicatorSize = 40.0,
this.indicatorColor = Colors.blueGrey,
this.forceInReleaseMode = false,
this.enabled = true,
}) : super(key: key);
@override
_TouchIndicatorState createState() => _TouchIndicatorState();
}
class _TouchIndicatorState extends State<TouchIndicator> {
Map<int, Offset> touchPositions = <int, Offset>{};
Iterable<Widget> buildTouchIndicators() sync* {
if (touchPositions.isNotEmpty) {
for (var touchPosition in touchPositions.values) {
yield Positioned.directional(
start: touchPosition.dx - widget.indicatorSize / 2,
top: touchPosition.dy - widget.indicatorSize / 2,
textDirection: TextDirection.ltr,
child: widget.indicator != null
? widget.indicator!
: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: widget.indicatorColor.withOpacity(0.3),
),
child: Icon(
Icons.fingerprint,
size: widget.indicatorSize,
color: widget.indicatorColor.withOpacity(0.9),
),
),
);
}
}
}
void savePointerPosition(int index, Offset position) {
setState(() {
touchPositions[index] = position;
});
}
void clearPointerPosition(int index) {
setState(() {
touchPositions.remove(index);
});
}
@override
Widget build(BuildContext context) {
if ((kReleaseMode && !widget.forceInReleaseMode) || !widget.enabled) {
return widget.child;
}
var children = [
widget.child,
...buildTouchIndicators(),
];
return Listener(
onPointerDown: (opm) {
savePointerPosition(opm.pointer, opm.position);
},
onPointerMove: (opm) {
savePointerPosition(opm.pointer, opm.position);
},
onPointerCancel: (opc) {
clearPointerPosition(opc.pointer);
},
onPointerUp: (opc) {
clearPointerPosition(opc.pointer);
},
child: Stack(children: children),
);
}
}