flutter/examples/layers/rendering/touch_input.dart
Ian Hickson 449f4a6673
License update (#45373)
* Update project.pbxproj files to say Flutter rather than Chromium

Also, the templates now have an empty organization so that we don't cause people to give their apps a Flutter copyright.

* Update the copyright notice checker to require a standard notice on all files

* Update copyrights on Dart files. (This was a mechanical commit.)

* Fix weird license headers on Dart files that deviate from our conventions; relicense Shrine.

Some were already marked "The Flutter Authors", not clear why. Their
dates have been normalized. Some were missing the blank line after the
license. Some were randomly different in trivial ways for no apparent
reason (e.g. missing the trailing period).

* Clean up the copyrights in non-Dart files. (Manual edits.)

Also, make sure templates don't have copyrights.

* Fix some more ORGANIZATIONNAMEs
2019-11-27 15:04:02 -08:00

137 lines
4.6 KiB
Dart

// Copyright 2014 The Flutter 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 = 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 incoming 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] = 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
// allotted 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, 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 = RenderParagraph(
const TextSpan(
style: 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 = RenderStack(
textDirection: TextDirection.ltr,
children: <RenderBox>[
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.
RenderingFlutterBinding(root: stack);
}