Skip to content

Instantly share code, notes, and snippets.

@CoderNamedHendrick
Last active December 27, 2022 16:40
Show Gist options
  • Save CoderNamedHendrick/ad3169274f627c907bc9dc4d1117096f to your computer and use it in GitHub Desktop.
Save CoderNamedHendrick/ad3169274f627c907bc9dc4d1117096f to your computer and use it in GitHub Desktop.
Quad selector widget
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Quadrant? groupQuad;
static const size = 300.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
children: [
QuadrantWidget(
quadrant: Quadrant.one,
size: size,
groupQuad: groupQuad,
onChanged: (value) {
setState(() => groupQuad = value);
},
),
QuadrantWidget(
quadrant: Quadrant.two,
size: size,
groupQuad: groupQuad,
onChanged: (value) {
setState(() => groupQuad = value);
},
),
QuadrantWidget(
quadrant: Quadrant.three,
size: size,
groupQuad: groupQuad,
onChanged: (value) {
setState(() => groupQuad = value);
},
),
QuadrantWidget(
quadrant: Quadrant.four,
size: size,
groupQuad: groupQuad,
onChanged: (value) {
setState(() => groupQuad = value);
},
),
GestureDetector(
onTap: () {
print('Tapped Area, EmojiPainter');
},
child: CustomPaint(
painter: const EmojiPainter(size),
child: SizedBox(
height: size,
width: size,
child: Align(
alignment: Alignment.center,
child: SizedBox(
width: 0.381 * size,
height: 0.381 * size,
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: Container(
// we got the 0.381 from our scale factor in emojiPainter.
width: 0.381 * size - 40,
height: 0.381 * size - 40,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
),
Align(
alignment: const Alignment(0.4, 0.65),
child: Container(
height: 20,
width: 20,
decoration: const BoxDecoration(
color: Colors.purple,
shape: BoxShape.circle,
),
),
)
],
),
),
),
),
),
),
],
),
),
);
}
}
enum Quadrant { one, two, three, four }
class QuadrantWidget extends StatelessWidget {
const QuadrantWidget(
{super.key,
required this.quadrant,
required this.size,
this.groupQuad,
this.onChanged,
this.iconData,
this.text});
final Quadrant quadrant;
final double size;
final Quadrant? groupQuad;
final ValueChanged<Quadrant>? onChanged;
final IconData? iconData;
final String? text;
bool get _selected => quadrant == groupQuad;
void updateValue(Quadrant value) {
onChanged?.call(value);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => updateValue(quadrant),
child: CustomPaint(
painter: QuadrantPainter(
quadrant: quadrant, isSelected: _selected, paintSize: size),
child: SizedBox(
height: size,
width: size,
child: Align(
alignment: _columnAlignment,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
iconData ?? Icons.screen_share,
color: _selected ? Colors.white : null,
),
Text(
text ?? 'Shared',
style: TextStyle(
color: _selected ? Colors.white : null,
),
)
],
),
),
),
),
);
}
Alignment get _columnAlignment {
switch (quadrant) {
case Quadrant.one:
return const Alignment(0.6, -0.6);
case Quadrant.two:
return const Alignment(-0.6, -0.6);
case Quadrant.three:
return const Alignment(-0.6, 0.6);
case Quadrant.four:
return const Alignment(0.6, 0.6);
}
}
}
class QuadrantPainter extends CustomPainter {
const QuadrantPainter(
{required this.quadrant,
required this.paintSize,
this.isSelected = false});
final Quadrant quadrant;
final bool isSelected;
final double paintSize;
static double get _sweepAngle {
return -pi / 2;
}
Path get _quadPath {
return Path()
..moveTo(paintSize / 2, paintSize / 2)
..lineTo(_movePosition.dx, _movePosition.dy)
..arcTo(
Rect.fromLTRB(0, 0, paintSize, paintSize),
_startPosition,
_sweepAngle,
false,
)
..close();
}
Offset get _center {
return Offset(paintSize / 2, paintSize / 2);
}
@override
void paint(Canvas canvas, Size size) {
final gradient = LinearGradient(
colors: const [Color(0xFF9c8cfb), Color(0xFF88dffa)],
begin: _alignmentPoints.a,
end: _alignmentPoints.b);
final paint = Paint()
..style = PaintingStyle.fill
..color = Colors.white30;
final selectPaint = Paint()
..style = PaintingStyle.fill
..shader =
gradient.createShader(Rect.fromPoints(_center, _gradientEndOffset));
if (!isSelected) {
final shadowPaint = Paint()
..color = Colors.black54.withOpacity(0.65)
..style = PaintingStyle.stroke
..maskFilter = MaskFilter.blur(BlurStyle.outer, sqrt(10));
canvas.save();
canvas.translate(0, 0);
canvas.drawPath(
Path()
..moveTo(_center.dx, _center.dy)
..lineTo(_movePosition.dx, _movePosition.dy),
shadowPaint);
canvas.restore();
}
canvas.drawPath(_quadPath, isSelected ? selectPaint : paint);
}
Offset get _movePosition {
switch (quadrant) {
case Quadrant.one:
return Offset(paintSize, paintSize / 2);
case Quadrant.two:
return Offset(paintSize / 2, 0);
case Quadrant.three:
return Offset(0, paintSize / 2);
case Quadrant.four:
return Offset(paintSize / 2, paintSize);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
@override
bool? hitTest(Offset position) {
return _quadPath.contains(position);
}
double get _startPosition {
switch (quadrant) {
case Quadrant.one:
return 0;
case Quadrant.two:
return 3 * pi / 2;
case Quadrant.three:
return pi;
case Quadrant.four:
return pi / 2;
}
}
Offset get _gradientEndOffset {
switch (quadrant) {
case Quadrant.one:
return Offset(paintSize, 0);
case Quadrant.two:
return const Offset(0, 0);
case Quadrant.three:
return Offset(0, paintSize);
case Quadrant.four:
return Offset(paintSize, paintSize);
}
}
AlignmentPoints get _alignmentPoints {
switch (quadrant) {
case Quadrant.one:
return const AlignmentPoints(Alignment.topRight, Alignment.bottomLeft);
case Quadrant.two:
return const AlignmentPoints(Alignment.topLeft, Alignment.bottomRight);
case Quadrant.three:
return const AlignmentPoints(Alignment.bottomLeft, Alignment.topRight);
case Quadrant.four:
return const AlignmentPoints(Alignment.bottomRight, Alignment.topLeft);
}
}
}
class EmojiPainter extends CustomPainter {
final double paintSize;
const EmojiPainter(this.paintSize);
Offset get _center {
return Offset(paintSize / 2, paintSize / 2);
}
double get _radius {
return (0.381 * paintSize) / 2;
}
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..color = Colors.white;
canvas.drawCircle(_center, _radius, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
@override
bool? hitTest(Offset position) {
Path path = Path()
..addOval(Rect.fromCircle(center: _center, radius: _radius));
return path.contains(position);
}
}
class AlignmentPoints {
final Alignment a;
final Alignment b;
const AlignmentPoints(this.a, this.b);
}
@CoderNamedHendrick
Copy link
Author

Mostly done.

@gboliknow
Copy link

This is super dope, if the designer talk anything ,na to give her keyboard make she go build herself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment