Last active
August 17, 2020 08:45
-
-
Save kangabru/883835ff2c160ef84d71a7552904c08d to your computer and use it in GitHub Desktop.
Allows you to display a 'magnifying glass' widget which helps users see what's under their finger while they are drawing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math'; | |
import 'dart:ui' as ui; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
/// The radius of the mag glass. | |
const double _RADIUS = 60.0; | |
/// The distance the mag glass will be offset from the touch point. | |
const double _OFFSET = _RADIUS * 1.5; | |
/// The furthest left and top position the mag glass can have. | |
const double _PADDING_MAG_LEFT = 50.0, _PADDING_MAG_TOP = -10.0; | |
mixin MagnifyingGlass<T extends StatefulWidget> on State<T> { | |
static GlobalKey _key = new GlobalKey(); | |
Offset _pos; | |
ui.Image _image; | |
bool _visible = false, _processing = false; | |
/// Wrap this around widget you wish to magnify. | |
Widget magnifyThis(Widget child) => RepaintBoundary(key: _key, child: child); | |
/// Show or hide the magnifying glass widget | |
showMagGlass(bool visible) => setState(() => _visible = visible); | |
/// Update the center position of the magnifying glass | |
updateMagGlassPosition(Offset position) => _updateMagPixels(position); | |
/// Draw the magnifying glass widget | |
Widget magnifyingGlass([Color background]) { | |
return Visibility( | |
visible: _visible, | |
child: EasyPaint(_MagGlass(_image, _pos, background)), | |
); | |
} | |
/// Takes a screenshot of the wrapped widgets and updates the mag glass image | |
/// Note that this whole widget only processes one screenshot at a time to improve | |
/// performance. There may be a slight image delay on lower powered devices. | |
_updateMagPixels(Offset pos) async { | |
setState(() => _pos = pos); | |
if (_processing) return; | |
setState(() => _processing = true); | |
RenderRepaintBoundary boundary = _key.currentContext.findRenderObject(); | |
ui.Image image = await boundary.toImage(); | |
setState(() { | |
_processing = false; | |
_image = image; | |
}); | |
} | |
} | |
/// Draws the actual magnifying glass with the given cropped image | |
class _MagGlass extends CustomPainter { | |
final Offset pos; | |
final ui.Image image; | |
final Color background; | |
_MagGlass(this.image, this.pos, this.background); | |
@override | |
void paint(Canvas canvas, Size size) { | |
if (image == null) return; | |
var src = Rect.fromCircle(center: pos, radius: _RADIUS); | |
// Calculate the mag glass position accounting for the left and top limits | |
var offsetX = max(_PADDING_MAG_LEFT, pos.dx - _OFFSET); | |
var offsetY = max(_PADDING_MAG_TOP, pos.dy - _OFFSET); | |
var offset = Offset(offsetX, offsetY); | |
var dst = Rect.fromCircle(center: offset, radius: _RADIUS); | |
Path path = Path(); | |
path.addOval(dst); | |
// Draw the image in a circle at the mag glass position | |
canvas.save(); | |
canvas.clipPath(path); | |
canvas.drawPaint(Paint()..color = background ?? Colors.transparent); | |
canvas.drawImageRect(image, src, dst, Paint()); | |
canvas.restore(); | |
// Draw a border around the mag glass | |
var paint = Paint() | |
..color = Colors.black | |
..style = PaintingStyle.stroke | |
..strokeWidth = 8.0; | |
canvas.drawOval(dst, paint); | |
} | |
bool shouldRepaint(_MagGlass other) => other.image.hashCode != image.hashCode; | |
} | |
class EasyPaint extends CustomPaint { | |
EasyPaint(CustomPainter painter) | |
: super(painter: painter, size: Size.infinite); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment