forked from flutter/flutter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
touch_input.dart
136 lines (119 loc) · 4.66 KB
/
touch_input.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This example shows how to use process input events in the underlying render
// tree.
import 'package:flutter/material.dart'; // Imported just for its color palette.
import 'package:flutter/rendering.dart';
// Material design colors. :p
List<Color> _kColors = <Color>[
Colors.teal,
Colors.amber,
Colors.purple,
Colors.lightBlue,
Colors.deepPurple,
Colors.lime,
];
/// A simple model object for a dot that reacts to pointer pressure.
class Dot {
Dot({ Color color }) : _paint = new Paint()..color = color;
final Paint _paint;
Offset position = Offset.zero;
double radius = 0.0;
void update(PointerEvent event) {
position = event.position;
radius = 5 + (95 * event.pressure);
}
void paint(Canvas canvas, Offset offset) {
canvas.drawCircle(position + offset, radius, _paint);
}
}
/// A render object that draws dots under each pointer.
class RenderDots extends RenderBox {
RenderDots();
/// State to remember which dots to paint.
final Map<int, Dot> _dots = <int, Dot>{};
/// Indicates that the size of this render object depends only on the
/// layout constraints provided by the parent.
@override
bool get sizedByParent => true;
/// By selecting the biggest value permitted by the incomming constraints
/// during layout, this function makes this render object as large as
/// possible (i.e., fills the entire screen).
@override
void performResize() {
size = constraints.biggest;
}
/// Makes this render object hittable so that it receives pointer events.
@override
bool hitTestSelf(Offset position) => true;
/// Processes pointer events by mutating state and invalidating its previous
/// painting commands.
@override
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is PointerDownEvent) {
final Color color = _kColors[event.pointer.remainder(_kColors.length)];
_dots[event.pointer] = new Dot(color: color)..update(event);
// We call markNeedsPaint to indicate that our painting commands have
// changed and that paint needs to be called before displaying a new frame
// to the user. It's harmless to call markNeedsPaint multiple times
// because the render tree will ignore redundant calls.
markNeedsPaint();
} else if (event is PointerUpEvent || event is PointerCancelEvent) {
_dots.remove(event.pointer);
markNeedsPaint();
} else if (event is PointerMoveEvent) {
_dots[event.pointer].update(event);
markNeedsPaint();
}
}
/// Issues new painting commands.
@override
void paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas;
// The "size" property indicates the size of that this render box was
// alotted during layout. Here we paint our bounds white. Notice that we're
// located at "offset" from the origin of the canvas' coordinate system.
// Passing offset during the render tree's paint walk is an optimization to
// avoid having to change the origin of the canvas's coordinate system too
// often.
canvas.drawRect(offset & size, new Paint()..color = const Color(0xFFFFFFFF));
// We iterate through our model and paint each dot.
for (Dot dot in _dots.values)
dot.paint(canvas, offset);
}
}
void main() {
// Create some styled text to tell the user to interact with the app.
final RenderParagraph paragraph = new RenderParagraph(
const TextSpan(
style: const TextStyle(color: Colors.black87),
text: "Touch me!",
),
textDirection: TextDirection.ltr,
);
// A stack is a render object that layers its children on top of each other.
// The bottom later is our RenderDots object, and on top of that we show the
// text.
final RenderStack stack = new RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[
new RenderDots(),
paragraph,
],
);
// The "parentData" field of a render object is controlled by the render
// object's parent render object. Now that we've added the paragraph as a
// child of the RenderStack, the paragraph's parentData field has been
// populated with a StackParentData, which we can use to provide input to the
// stack's layout algorithm.
//
// We use the StackParentData of the paragraph to position the text in the top
// left corner of the screen.
final StackParentData paragraphParentData = paragraph.parentData;
paragraphParentData
..top = 40.0
..left = 20.0;
// Finally, we attach the render tree we've built to the screen.
new RenderingFlutterBinding(root: stack);
}