I’m currently working on a Flutter project and am facing challenges in creating a tooth selection UI with 32 teeth. The UI should be in a oval form, and each tooth needs to be selectable with an icon that changes color when selected.
I’ve attempted various approaches, including using Stack and Positioned, as well as exploring the Flutter Shape Maker website (https://fluttershapemaker.com/).
However, I’ve encountered issues with teeth overlapping or not being positioned correctly.
similar idea is here in that link :
https://codepen.io/johnstuif/pen/JdOXWa .
are there any alternative libraries or methods better suited for creating this type of UI?
For clarity, I have attached an image illustrating the desired UI :
I tried the code from https://fluttershapemaker.com/ so i used CustomPainter but it didnt work properly ! , this is the code :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'dart:ui' as ui;
import '../widgets/testselectedteeth.dart';
class Test extends StatefulWidget {
const Test({super.key});
@override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
@override
Widget build(BuildContext context) {
return Container(child: Center(
child: Center(
child: CustomPaint(
size: Size(Get.width, (Get.width*1.2188841201716738).toDouble()), //You can Replace [WIDTH] with your desired width for Custom Paint and height will be calculated automatically
painter: RPSCustomPainter(),
)
)
),
);
}
}
//Copy this CustomPainter code to the Bottom of the File
class RPSCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint_0_fill = Paint()..style=PaintingStyle.fill;
paint_0_fill.color = Color(0xffffffff).withOpacity(1.0);
canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(0,0,size.width,size.height),bottomRight: Radius.circular(size.width*0.02432046),bottomLeft: Radius.circular(size.width*0.02432046),topLeft: Radius.circular(size.width*0.02432046),topRight: Radius.circular(size.width*0.02432046)),paint_0_fill);
Paint paint_1_stroke = Paint()..style=PaintingStyle.stroke..strokeWidth=size.width*0.0007153076;
paint_1_stroke.color=Color(0xffdae1eb).withOpacity(1.0);
canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(size.width*0.0003576538,size.height*0.0002934272,size.width*0.9992847,size.height*0.9994131),bottomRight: Radius.circular(size.width*0.02396280),bottomLeft: Radius.circular(size.width*0.02396280),topLeft: Radius.circular(size.width*0.02396280),topRight: Radius.circular(size.width*0.02396280)),paint_1_stroke);
Path path_2 = Path();
path_2.moveTo(size.width*0.05117506,size.height*0.05854166);
path_2.cubicTo(size.width*0.04289034,size.height*0.05854162,size.width*0.01769391,size.height*0.05709627,size.width*0.009796846,size.height*0.05244336);
path_2.lineTo(size.width*0.009789679,size.height*0.05243913);
path_2.lineTo(size.width*0.009782254,size.height*0.05243520);
path_2.cubicTo(size.width*0.008867504,size.height*0.05195051,size.width*0.006506474,size.height*0.05030248,size.width*0.004452697,size.height*0.04846885);
path_2.cubicTo(size.width*0.001838086,size.height*0.04613452,size.width*0.0004222647,size.height*0.04417941,size.width*0.0003578660,size.height*0.04281425);
path_2.cubicTo(size.width*0.0003319522,size.height*0.03979083,size.width*0.002672476,size.height*0.03561353,size.width*0.004737604,size.height*0.03192767);
path_2.cubicTo(size.width*0.005781582,size.height*0.03006436,size.width*0.006767662,size.height*0.02830438,size.width*0.007241825,size.height*0.02700950);
path_2.lineTo(size.width*0.007319335,size.height*0.02678887);
path_2.cubicTo(size.width*0.01149954,size.height*0.01487530,size.width*0.01566505,size.height*0.006847222,size.width*0.01904950,size.height*0.004181510);
path_2.cubicTo(size.width*0.02376568,size.height*0.0007554657,size.width*0.02894936,size.height*0.0002934321,size.width*0.03339841,size.height*0.0002934321);
path_2.cubicTo(size.width*0.03570410,size.height*0.0002934321,size.width*0.03810776,size.height*0.0004343241,size.width*0.04065255,size.height*0.0005834908);
path_2.cubicTo(size.width*0.04347474,size.height*0.0007489250,size.width*0.04639303,size.height*0.0009199814,size.width*0.04949589,size.height*0.0009199814);
path_2.cubicTo(size.width*0.05584766,size.height*0.0009199814,size.width*0.06164476,size.height*0.001623655,size.width*0.06672616,size.height*0.003011460);
path_2.cubicTo(size.width*0.07210879,size.height*0.004481531,size.width*0.07657636,size.height*0.006694723,size.width*0.08000476,size.height*0.009589536);
path_2.cubicTo(size.width*0.08567570,size.height*0.01437790,size.width*0.08840723,size.height*0.02090861,size.width*0.08812347,size.height*0.02900025);
path_2.cubicTo(size.width*0.08795212,size.height*0.03388650,size.width*0.08693743,size.height*0.03827536,size.width*0.08510760,size.height*0.04204490);
path_2.cubicTo(size.width*0.08334477,size.height*0.04567644,size.width*0.08080683,size.height*0.04877303,size.width*0.07756432,size.height*0.05124865);
path_2.cubicTo(size.width*0.07440765,size.height*0.05365873,size.width*0.07055773,size.height*0.05550105,size.width*0.06612150,size.height*0.05672445);
path_2.cubicTo(size.width*0.06174984,size.height*0.05793004,size.width*0.05678756,size.height*0.05854133,size.width*0.05137254,size.height*0.05854133);
path_2.cubicTo(size.width*0.05130722,size.height*0.05854155,size.width*0.05124205,size.height*0.05854166,size.width*0.05117506,size.height*0.05854166);
path_2.close();
Paint paint_2_fill = Paint()..style=PaintingStyle.fill;
paint_2_fill.color = Color(0xffa7a3dd).withOpacity(1.0);
canvas.drawPath(path_2,paint_2_fill);
Path path_3 = Path();
path_3.moveTo(size.width*0.05117506,size.height*0.05883509);
path_3.lineTo(size.width*0.05117506,size.height*0.05824823);
path_3.cubicTo(size.width*0.05124152,size.height*0.05824823,size.width*0.05130619,size.height*0.05824813,size.width*0.05137254,size.height*0.05824790);
path_3.cubicTo(size.width*0.05674875,size.height*0.05824790,size.width*0.06167267,size.height*0.05764176,size.width*0.06600754,size.height*0.05644632);
path_3.cubicTo(size.width*0.07039522,size.height*0.05523631,size.width*0.07420151,size.height*0.05341529,size.width*0.07732067,size.height*0.05103385);
path_3.cubicTo(size.width*0.08052413,size.height*0.04858805,size.width*0.08303224,size.height*0.04552720,size.width*0.08477533,size.height*0.04193633);
path_3.cubicTo(size.width*0.08658962,size.height*0.03819880,size.width*0.08759582,size.height*0.03384363,size.width*0.08776597,size.height*0.02899181);
path_3.cubicTo(size.width*0.08804685,size.height*0.02098242,size.width*0.08534929,size.height*0.01452336,size.width*0.07974825,size.height*0.009794019);
path_3.cubicTo(size.width*0.07636018,size.height*0.006933256,size.width*0.07194091,size.height*0.004744934,size.width*0.06661320,size.height*0.003289864);
path_3.cubicTo(size.width*0.06156829,size.height*0.001912024,size.width*0.05580919,size.height*0.001213409,size.width*0.04949589,size.height*0.001213409);
path_3.cubicTo(size.width*0.04638026,size.height*0.001213409,size.width*0.04345552,size.height*0.001041965,size.width*0.04062706,size.height*0.0008761786);
path_3.cubicTo(size.width*0.03808881,size.height*0.0007273875,size.width*0.03569134,size.height*0.0005868593,size.width*0.03339841,size.height*0.0005868593);
path_3.cubicTo(size.width*0.03043328,size.height*0.0005868593,size.width*0.02806493,size.height*0.0008273992,size.width*0.02594504,size.height*0.001343843);
path_3.cubicTo(size.width*0.02346706,size.height*0.001947538,size.width*0.02129077,size.height*0.002946318,size.width*0.01929215,size.height*0.004397163);
path_3.cubicTo(size.width*0.01715795,size.height*0.006081325,size.width*0.01462593,size.height*0.01008079,size.width*0.01196878,size.height*0.01596501);
path_3.cubicTo(size.width*0.009818878,size.height*0.02072589,size.width*0.008196245,size.height*0.02535038,size.width*0.007663026,size.height*0.02687004);
path_3.lineTo(size.width*0.007584357,size.height*0.02709393);
path_3.cubicTo(size.width*0.007103041,size.height*0.02840837,size.width*0.006157461,size.height*0.03009605,size.width*0.005062569,size.height*0.03205022);
path_3.cubicTo(size.width*0.003115564,size.height*0.03552526,size.width*0.0006929543,size.height*0.03984942,size.width*0.0007154826,size.height*0.04280757);
path_3.cubicTo(size.width*0.0007790998,size.height*0.04408385,size.width*0.002199298,size.height*0.04602336,size.width*0.004716045,size.height*0.04827032);
path_3.cubicTo(size.width*0.006918534,size.height*0.05023672,size.width*0.009228849,size.height*0.05179267,size.width*0.009976302,size.height*0.05218871);
path_3.lineTo(size.width*0.01000547,size.height*0.05220503);
path_3.cubicTo(size.width*0.01340772,size.height*0.05420962,size.width*0.02059806,size.height*0.05586476,size.width*0.03079918,size.height*0.05699152);
path_3.cubicTo(size.width*0.03979848,size.height*0.05798554,size.width*0.04806258,size.height*0.05824822,size.width*0.05117506,size.height*0.05824823);
path_3.lineTo(size.width*0.05117506,size.height*0.05883509);
path_3.moveTo(size.width*0.05117506,size.height*0.05883509);
path_3.cubicTo(size.width*0.04382050,size.height*0.05883506,size.width*0.01780169,size.height*0.05752104,size.width*0.009588220,size.height*0.05268169);
path_3.cubicTo(size.width*0.007822196,size.height*0.05174594,size.width*0.0001532267,size.height*0.04619955,size.width*2.653126e-7,size.height*0.04282104);
path_3.cubicTo(size.width*-0.00004359735,size.height*0.03812524,size.width*0.005534400,size.height*0.03065252,size.width*0.006899293,size.height*0.02692508);
path_3.cubicTo(size.width*0.007755115,size.height*0.02449403,size.width*0.01334569,size.height*0.008259782,size.width*0.01880710,size.height*0.003965674);
path_3.cubicTo(size.width*0.02721102,size.height*-0.002143621,size.width*0.03709277,size.height*0.0006265542,size.width*0.04949589,size.height*0.0006265542);
path_3.cubicTo(size.width*0.07121770,size.height*0.0006265424,size.width*0.08918626,size.height*0.008897387,size.width*0.08848098,size.height*0.02900869);
path_3.cubicTo(size.width*0.08777570,size.height*0.04911998,size.width*0.07309436,size.height*0.05883476,size.width*0.05137254,size.height*0.05883476);
path_3.cubicTo(size.width*0.05130821,size.height*0.05883498,size.width*0.05124256,size.height*0.05883509,size.width*0.05117506,size.height*0.05883509);
path_3.close();
Paint paint_3_fill = Paint()..style=PaintingStyle.fill;
paint_3_fill.color = Color(0xff000000).withOpacity(1.0);
canvas.drawPath(path_3,paint_3_fill);
Path path_4 = Path();
path_4.moveTo(size.width*0.03568493,size.height*0.04873402);
path_4.cubicTo(size.width*0.02072166,size.height*0.04873402,size.width*0.01151754,size.height*0.03570276,size.width*0.005170671,size.height*0.02434997);
path_4.lineTo(size.width*0.004823818,size.height*0.02373040);
path_4.cubicTo(size.width*0.003182287,size.height*0.02080017,size.width*0.001631801,size.height*0.01803243,size.width*0.0008590400,size.height*0.01546018);
path_4.cubicTo(size.width*0.000004848288,size.height*0.01261681,size.width*0.0002322589,size.height*0.01043470,size.width*0.001574762,size.height*0.008592940);
path_4.cubicTo(size.width*0.003154362,size.height*0.006425897,size.width*0.006308110,size.height*0.004736918,size.width*0.01121624,size.height*0.003429501);
path_4.cubicTo(size.width*0.01671309,size.height*0.001965264,size.width*0.02429247,size.height*0.001003304,size.width*0.03438748,size.height*0.0004886674);
path_4.cubicTo(size.width*0.03692873,size.height*0.0003591134,size.width*0.03934453,size.height*0.0002934326,size.width*0.04156781,size.height*0.0002934326);
path_4.cubicTo(size.width*0.04778265,size.height*0.0002934326,size.width*0.05284011,size.height*0.0008076580,size.width*0.05659971,size.height*0.001821848);
path_4.cubicTo(size.width*0.05992714,size.height*0.002719442,size.width*0.06234814,size.height*0.004041026,size.width*0.06379548,size.height*0.005749888);
path_4.cubicTo(size.width*0.06542783,size.height*0.007677165,size.width*0.06591496,size.height*0.01015898,size.width*0.06528473,size.height*0.01333719);
path_4.cubicTo(size.width*0.06472583,size.height*0.01615572,size.width*0.06341363,size.height*0.01904874,size.width*0.06214462,size.height*0.02184651);
path_4.cubicTo(size.width*0.06168499,size.height*0.02285985,size.width*0.06125084,size.height*0.02381701,size.width*0.06086682,size.height*0.02474123);
path_4.cubicTo(size.width*0.06066591,size.height*0.02522478,size.width*0.06046409,size.height*0.02571463,size.width*0.06026036,size.height*0.02620918);
path_4.cubicTo(size.width*0.05821921,size.height*0.03116374,size.width*0.05590575,size.height*0.03677935,size.width*0.05231088,size.height*0.04109529);
path_4.cubicTo(size.width*0.04822286,size.height*0.04600331,size.width*0.04307797,size.height*0.04849693,size.width*0.03658219,size.height*0.04871864);
path_4.cubicTo(size.width*0.03628326,size.height*0.04872884,size.width*0.03598139,size.height*0.04873402,size.width*0.03568493,size.height*0.04873402);
path_4.close();
Paint paint_4_fill = Paint()..style=PaintingStyle.fill;
paint_4_fill.color = Color(0xffa7a3dd).withOpacity(1.0);
canvas.drawPath(path_4,paint_4_fill);
// and more ...
Paint paint_78_fill = Paint()..style=PaintingStyle.fill;
paint_78_fill.color = Color(0xffa7a3dd).withOpacity(1.0);
canvas.drawPath(path_78,paint_78_fill);
Path path_79 = Path();
path_79.moveTo(size.width*0.05142241,size.height*0.06928314);
path_79.lineTo(size.width*0.05142241,size.height*0.06869628);
path_79.lineTo(size.width*0.05158066,size.height*0.06869601);
path_79.cubicTo(size.width*0.06223917,size.height*0.06869600,size.width*0.07315905,size.height*0.06529163,size.width*0.08154031,size.height*0.05935583);
path_79.cubicTo(size.width*0.08585187,size.height*0.05630230,size.width*0.08928567,size.height*0.05274150,size.width*0.09174637,size.height*0.04877238);
path_79.cubicTo(size.width*0.09437383,size.height*0.04453425,size.width*0.09579065,size.height*0.03997355,size.width*0.09595748,size.height*0.03521695);
path_79.cubicTo(size.width*0.09611638,size.height*0.03068593,size.width*0.09536793,size.height*0.02642978,size.width*0.09373296,size.height*0.02256674);
path_79.cubicTo(size.width*0.09209037,size.height*0.01868573,size.width*0.08960145,size.height*0.01531958,size.width*0.08633536,size.height*0.01256181);
path_79.cubicTo(size.width*0.08009148,size.height*0.007289672,size.width*0.07125378,size.height*0.004502981,size.width*0.06077768,size.height*0.004502981);
path_79.cubicTo(size.width*0.05726373,size.height*0.004502981,size.width*0.05353583,size.height*0.004817125,size.width*0.04969754,size.height*0.005436690);
path_79.lineTo(size.width*0.04962915,size.height*0.005447735);
path_79.lineTo(size.width*0.04955945,size.height*0.005447735);
path_79.cubicTo(size.width*0.04568095,size.height*0.005447746,size.width*0.04179133,size.height*0.004293475,size.width*0.03767331,size.height*0.003071444);
path_79.cubicTo(size.width*0.03355714,size.height*0.001849942,size.width*0.02930081,size.height*0.0005868547,size.width*0.02507984,size.height*0.0005868547);
path_79.cubicTo(size.width*0.02237299,size.height*0.0005868547,size.width*0.01992540,size.height*0.001100364,size.width*0.01759724,size.height*0.002156737);
path_79.cubicTo(size.width*0.01490188,size.height*0.003379713,size.width*0.01240780,size.height*0.005299856,size.width*0.009973057,size.height*0.008026382);
path_79.cubicTo(size.width*0.008193026,size.height*0.01015761,size.width*0.006870651,size.height*0.01231404,size.width*0.006042500,size.height*0.01443601);
path_79.cubicTo(size.width*0.005335761,size.height*0.01624691,size.width*0.004968465,size.height*0.01808864,size.width*0.004950826,size.height*0.01991002);
path_79.cubicTo(size.width*0.004918451,size.height*0.02325195,size.width*0.006042271,size.height*0.02596329,size.width*0.006862843,size.height*0.02794302);
path_79.cubicTo(size.width*0.007483473,size.height*0.02944034,size.width*0.007931885,size.height*0.03052218,size.width*0.007650225,size.height*0.03132227);
path_79.lineTo(size.width*0.007648065,size.height*0.03132828);
path_79.cubicTo(size.width*0.007166749,size.height*0.03264275,size.width*0.006221155,size.height*0.03433045,size.width*0.005126248,size.height*0.03628465);
path_79.cubicTo(size.width*0.003177235,size.height*0.03976328,size.width*0.0007516270,size.height*0.04409255,size.width*0.0007792665,size.height*0.04705091);
path_79.lineTo(size.width*0.0007795956,size.height*0.04708717);
path_79.lineTo(size.width*0.0007744883,size.height*0.04712319);
path_79.cubicTo(size.width*0.0003597386,size.height*0.05004961,size.width*0.002127693,size.height*0.05311405,size.width*0.006029224,size.height*0.05623139);
path_79.cubicTo(size.width*0.009229667,size.height*0.05878855,size.width*0.01296161,size.height*0.06064540,size.width*0.01455522,size.height*0.06143830);
path_79.cubicTo(size.width*0.01481524,size.height*0.06156767,size.width*0.01502182,size.height*0.06167046,size.width*0.01516382,size.height*0.06174541);
path_79.cubicTo(size.width*0.02107513,size.height*0.06466784,size.width*0.02902164,size.height*0.06633468,size.width*0.03464872,size.height*0.06721869);
path_79.cubicTo(size.width*0.04159077,size.height*0.06830926,size.width*0.04802332,size.height*0.06869625,size.width*0.05142241,size.height*0.06869628);
path_79.lineTo(size.width*0.05142241,size.height*0.06928314);
path_79.moveTo(size.width*0.05142241,size.height*0.06928313);
path_79.cubicTo(size.width*0.04423216,size.height*0.06928308,size.width*0.02573646,size.height*0.06766158,size.width*0.01478529,size.height*0.06224344);
path_79.cubicTo(size.width*0.01301927,size.height*0.06130769,size.width*-0.001061721,size.height*0.05499817,size.width*0.00006397323,size.height*0.04705541);
path_79.cubicTo(size.width*0.00002011057,size.height*0.04235960,size.width*0.005598122,size.height*0.03488689,size.width*0.006963001,size.height*0.03115943);
path_79.cubicTo(size.width*0.007818823,size.height*0.02872839,size.width*-0.001106299,size.height*0.02024555,size.width*0.009389366,size.height*0.007687031);
path_79.cubicTo(size.width*0.02318283,size.height*-0.007768565,size.width*0.03715639,size.height*0.004860892,size.width*0.04955945,size.height*0.004860880);
path_79.cubicTo(size.width*0.08028566,size.height*-0.00009890341,size.width*0.09737776,size.height*0.01512252,size.width*0.09667248,size.height*0.03523383);
path_79.cubicTo(size.width*0.09596716,size.height*0.05534512,size.width*0.07330239,size.height*0.06928284,size.width*0.05158066,size.height*0.06928286);
path_79.cubicTo(size.width*0.05152842,size.height*0.06928304,size.width*0.05147591,size.height*0.06928313,size.width*0.05142241,size.height*0.06928313);
path_79.close();
Paint paint_79_fill = Paint()..style=PaintingStyle.fill;
paint_79_fill.color = Color(0xff000000).withOpacity(1.0);
canvas.drawPath(path_79,paint_79_fill);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
2
Answers
This is my example:
i have simplified your svg file, add it to
assets/teeth.svg
:now you need to parse it somehow – you need two extra packages:
and this is a custom
StatefulWidget
widget to show it all: