Skip to content

Instantly share code, notes, and snippets.

@savioserra
Created January 30, 2020 14:59
Show Gist options
  • Save savioserra/b8d8a8f7c6646bb10ede2b868d304979 to your computer and use it in GitHub Desktop.
Save savioserra/b8d8a8f7c6646bb10ede2b868d304979 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
import 'dart:math' as Math;
enum MarkerType { cross, circle, none }
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [MyWidget(MarkerType.cross), MyWidget(MarkerType.circle)],
),
),
),
);
}
}
class MyWidget extends StatefulWidget {
final MarkerType type;
MyWidget(this.type);
@override
MyWidgetState createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
bool checked = false;
@override
Widget build(BuildContext context) {
return Container(
height: 60,
width: 60,
decoration: BoxDecoration(
border: Border.all(color: Colors.black12, width: 1),
shape: BoxShape.circle,
),
child: GestureDetector(
onTap: () => setState(() => checked = !checked),
child: TicTacToeMarker(type: widget.type, checked: checked)),
);
}
}
class TicTacToeMarker extends StatelessWidget {
final bool checked;
final MarkerType type;
final Gradient gradient;
final double strokeWidth;
const TicTacToeMarker({
Key key,
@required this.type,
this.checked = false,
this.strokeWidth = 6.0,
this.gradient = const LinearGradient(
colors: [Colors.orangeAccent, Colors.red],
begin: Alignment.topLeft,
),
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(strokeWidth / 2),
child: RepaintBoundary(
child: TweenAnimationBuilder(
duration: const Duration(milliseconds: 140),
tween: Tween<double>(begin: 0, end: checked ? 1.0 : 0.0),
builder: (ctx, value, child) => CustomPaint(
painter: MarkerPainter(
type,
clip: value,
gradient: gradient,
strokeWidth: strokeWidth,
),
),
),
),
);
}
}
class MarkerPainter extends CustomPainter {
final double clip;
final MarkerType type;
final Gradient gradient;
final double strokeWidth;
const MarkerPainter(
this.type, {
@required this.clip,
@required this.gradient,
@required this.strokeWidth,
});
@override
void paint(Canvas canvas, Size size) {
if (clip == 0 || type == MarkerType.none) return;
var gradientShader = gradient.createShader(Offset.zero & size);
var paint = Paint()
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke
..strokeJoin = StrokeJoin.round
..strokeCap = StrokeCap.round
..shader = gradientShader;
if (type == MarkerType.cross) {
paintClippingCross(canvas, size, paint);
} else {
paintClippingCircle(canvas, size, paint);
}
}
void paintClippingCross(Canvas canvas, Size size, Paint paint) {
var path = Path();
var currClip = clip * 2;
var firstLine = size.width * Math.min(1, currClip);
path.lineTo(firstLine, firstLine);
if (clip > 0.5) {
var secondLine = (currClip - 1) * size.width;
path
..moveTo(0, size.height)
..relativeLineTo(secondLine, -secondLine);
}
canvas.drawPath(path, paint);
}
void paintClippingCircle(Canvas canvas, Size size, Paint paint) {
var path = Path();
path.addArc(Offset.zero & size, 0, 2 * Math.pi * clip);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(MarkerPainter oldDelegate) =>
oldDelegate.clip != clip || oldDelegate.type != type;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment