Flutter: redraw Custompaint lines after changing scale - flutter

I am creating a note-taking app using Flutter and I use a CustomPainter for the drawing part. For better performance, the CustomPaint gets converted into an image after some Lines. Now the problem with images is when zooming in, the lines (which are Images now) are very pixelated. Now my first Idea to solve this was redrawing the lines after zooming.
But how do I redraw them correctly without them still having a bad resolution? Also, is it possible to only redraw the lines that are visible on the screen currently?
everything is wrapped with a layoutbuilder which provides constraints + pixelratio (scale):
LayoutBuilder(builder: (context, constraints) {
size = constraints.biggest;
scale = MediaQuery.of(context).devicePixelRatio;
How I did the zooming:
GestureDetector(
onScaleStart: (details) {
_initialFocalPoint = details.focalPoint;
_initialScale = _scale;
},
onScaleUpdate: (details) {
setState(() {
_sessionOffset =
details.focalPoint - _initialFocalPoint;
_scale = _initialScale * details.scale;
});
},
onScaleEnd: (details) {
setState(() {
_offset += _sessionOffset;
_sessionOffset = Offset.zero;
});
},
child: Transform.translate(
offset: _offset + _sessionOffset,
child: Transform.scale(
scale: _scale,
child: ....
my CustomPaint which comes somewhere after the Transform widgets:
CustomPaint(
size: size!,
willChange: true,
painter: DrawingViewPainter(
pointsList: drawingNotifier.points,
image: image
),
);
snippet with the custpmpaint to image converter (drawn lines get converted to images to save performance):
ui.PictureRecorder recorder = ui.PictureRecorder();
Canvas canvas = ui.Canvas(recorder);
canvas.scale(scale!);
DrawingViewPainter(image: image, pointsList: points).paint(canvas, size!);
ui.Picture picture = recorder.endRecording();
ui.Image newImage = await picture.toImage(
(size!.width * scale!).ceil(),
(size!.height * scale!).ceil(),
);
......
image = newImage
the Custompaint part with the image drawer:
canvas.drawImageRect(
image!,
Offset.zero & Size(image!.width.toDouble(), image!.height.toDouble()),
Offset.zero & size,
Paint());
}
(sorry for the huge amount of code)
If you know of a better way please let me know as well.
Here a video of the Problem

Related

How can I change color with GestureDetector of svg image and Flutter?

I need your help, I'am developing an app where the user will select any SVG image previously converted with flutterShapeMaker to get and set several classes as you see below (fragment example, I have 20 classes)
class PathUno extends CustomPainter{
final Color color;
PathUno(this.color);
#override
void paint(Canvas canvas, Size size) {
Path path_1 = Path();
path_1.moveTo(size.width*0.7138889,size.height*0.3569444);
path_1.cubicTo(size.width*0.7259804,size.height*0.3599747,size.width*0.7367647,size.height*0.3650253,size.width*0.7468954,size.height*0.3705808);
path_1.cubicTo(size.width*0.7586601,size.height*0.3771465,size.width*0.7694444,size.height*0.3844697,size.width*0.7761438,size.height*0.3949495);
path_1.cubicTo(size.width*0.7823529,size.height*0.4047980,size.width*0.7794118,size.height*0.4148990,size.width*0.7638889,size.height*0.4190657);
path_1.cubicTo(size.width*0.7485294,size.height*0.4231061,size.width*0.7339869,size.height*0.4217172,size.width*0.7187908,size.height*0.4193182);
path_1.cubicTo(size.width*0.7040850,size.height*0.4169192,size.width*0.6892157,size.height*0.4148990,size.width*0.6750000,size.height*0.4111111);
path_1.cubicTo(size.width*0.6684641,size.height*0.4093434,size.width*0.6620915,size.height*0.4073232,size.width*0.6552288,size.height*0.4061869);
path_1.cubicTo(size.width*0.6517974,size.height*0.4055556,size.width*0.6500000,size.height*0.4053030,size.width*0.6517974,size.height*0.4088384);
path_1.cubicTo(size.width*0.6647059,size.height*0.4327020,size.width*0.6648693,size.height*0.4574495,size.width*0.6612745,size.height*0.4825758);
path_1.cubicTo(size.width*0.6583333,size.height*0.5037879,size.width*0.6514706,size.height*0.5243687,size.width*0.6449346,size.height*0.5450758);
path_1.cubicTo(size.width*0.6436275,size.height*0.5491162,size.width*0.6431373,size.height*0.5532828,size.width*0.6421569,size.height*0.5574495);
path_1.cubicTo(size.width*0.6415033,size.height*0.5599747,size.width*0.6424837,size.height*0.5606061,size.width*0.6457516,size.height*0.5606061);
path_1.cubicTo(size.width*0.6566993,size.height*0.5606061,size.width*0.6648693,size.height*0.5648990,size.width*0.6709150,size.height*0.5715909);
path_1.cubicTo(size.width*0.6844771,size.height*0.5866162,size.width*0.6910131,size.height*0.6037879,size.width*0.6968954,size.height*0.6212121);
path_1.cubicTo(size.width*0.7052288,size.height*0.6462121,size.width*0.7102941,size.height*0.6715909,size.width*0.7142157,size.height*0.6972222);
path_1.cubicTo(size.width*0.7200980,size.height*0.7352273,size.width*0.7227124,size.height*0.7733586,size.width*0.7248366,size.height*0.8114899);
path_1.cubicTo(size.width*0.5620915,size.height*0.8372475,size.width*0.5602941,size.height*0.8338384,size.width*0.5599673,size.height*0.8303030);
path_1.cubicTo(size.width*0.5596405,size.height*0.8271465,size.width*0.5578431,size.height*0.8270202,size.width*0.5545752,size.height*0.8270202);
path_1.cubicTo(size.width*0.5460784,size.height*0.8271465,size.width*0.5377451,size.height*0.8271465,size.width*0.5292484,size.height*0.8271465);
path_1.cubicTo(size.width*0.5276144,size.height*0.8271465,size.width*0.5259804,size.height*0.8271465,size.width*0.5245098,size.height*0.8268939);
path_1.cubicTo(size.width*0.5163399,size.height*0.8252525,size.width*0.5160131,size.height*0.8251263,size.width*0.5147059,size.height*0.8316919);
path_1.cubicTo(size.width*0.5114379,size.height*0.8479798,size.width*0.4944444,size.height*0.8568182,size.width*0.4725490,size.height*0.8595960);
path_1.cubicTo(size.width*0.4442810,size.height*0.8631313,size.width*0.4156863,size.height*0.8623737,size.width*0.3870915,size.height*0.8607323);
path_1.cubicTo(size.width*0.3813725,size.height*0.8603535,size.width*0.3756536,size.height*0.8597222,size.width*0.3699346,size.height*0.8584596);
path_1.cubicTo(size.width*0.3537582,size.height*0.8547980,size.width*0.3470588,size.height*0.8459596,size.width*0.3511438,size.height*0.8343434);
path_1.cubicTo(size.width*0.6258170,size.height*0.4420455,size.width*0.6251634,size.height*0.4385101,size.width*0.6210784,size.height*0.4417929);
path_1.cubicTo(size.width*0.6168301,size.height*0.4426768,size.width*0.6125817,size.height*0.4435606,size.width*0.6083333,size.height*0.4444444);
path_1.cubicTo(size.width*0.6075163,size.height*0.4454545,size.width*0.6060458,size.height*0.4464646,size.width*0.6058824,size.height*0.4474747);
path_1.cubicTo(size.width*0.6055556,size.height*0.4508838,size.width*0.6042484,size.height*0.4522727,size.width*0.6000000,size.height*0.4502525);
path_1.cubicTo(size.width*0.5967320,size.height*0.4494949,size.width*0.5982026,size.height*0.4453283,size.width*0.5931373,size.height*0.4453283);
path_1.cubicTo(size.width*0.5754902,size.height*0.4452020,size.width*0.5584967,size.height*0.4428030,size.width*0.5418301,size.height*0.4375000);
path_1.cubicTo(size.width*0.5294118,size.height*0.4335859,size.width*0.5174837,size.height*0.4291667,size.width*0.5058824,size.height*0.4238636);
path_1.cubicTo(size.width*0.5029412,size.height*0.4226010,size.width*0.5001634,size.height*0.4210859,size.width*0.4973856,size.height*0.4196970);
path_1.cubicTo(size.width*0.4913399,size.height*0.4165404,size.width*0.4859477,size.height*0.4125000,size.width*0.4787582,size.height*0.4106061);
path_1.cubicTo(size.width*0.4805556,size.height*0.4078283,size.width*0.4846405,size.height*0.4075758,size.width*0.4875817,size.height*0.4063131);
path_1.cubicTo(size.width*0.4995098,size.height*0.4178030,size.width*0.5339869,size.height*0.4214646,size.width*0.5500000,size.height*0.4135101);
path_1.cubicTo(size.width*0.5580065,size.height*0.4094697,size.width*0.5637255,size.height*0.4003788,size.width*0.5560458,size.height*0.3925505);
path_1.cubicTo(size.width*0.5537582,size.height*0.3902778,size.width*0.5508170,size.height*0.3883838,size.width*0.5488562,size.height*0.3853535);
path_1.cubicTo(size.width*0.5503268,size.height*0.3852273,size.width*0.5511438,size.height*0.3849747,size.width*0.5521242,size.height*0.3849747);
path_1.cubicTo(size.width*0.5683007,size.height*0.3848485,size.width*0.5843137,size.height*0.3842172,size.width*0.6003268,size.height*0.3813131);
path_1.cubicTo(size.width*0.6169935,size.height*0.3782828,size.width*0.6333333,size.height*0.3750000,size.width*0.6477124,size.height*0.3672980);
path_1.cubicTo(size.width*0.6532680,size.height*0.3642677,size.width*0.6576797,size.height*0.3604798,size.width*0.6609477,size.height*0.3560606);
path_1.cubicTo(size.width*0.6650327,size.height*0.3506313,size.width*0.6635621,size.height*0.3434343,size.width*0.6570261,size.height*0.3402778);
path_1.cubicTo(size.width*0.6452614,size.height*0.3344697,size.width*0.6316993,size.height*0.3319444,size.width*0.6181373,size.height*0.3339646);
path_1.cubicTo(size.width*0.6083333,size.height*0.3353535,size.width*0.5985294,size.height*0.3363636,size.width*0.5887255,size.height*0.3377525);
path_1.cubicTo(size.width*0.5885621,size.height*0.3366162,size.width*0.5895425,size.height*0.3359848,size.width*0.5905229,size.height*0.3353535);
path_1.cubicTo(size.width*0.5919935,size.height*0.3345960,size.width*0.5933007,size.height*0.3337121,size.width*0.5949346,size.height*0.3330808);
path_1.cubicTo(size.width*0.6163399,size.height*0.3246212,size.width*0.6362745,size.height*0.3143939,size.width*0.6547386,size.height*0.3023990);
path_1.cubicTo(size.width*0.6637255,size.height*0.2965909,size.width*0.6718954,size.height*0.2904040,size.width*0.6774510,size.height*0.2823232);
path_1.cubicTo(size.width*0.6833333,size.height*0.2736111,size.width*0.6800654,size.height*0.2698232,size.width*0.6718954,size.height*0.2671717);
path_1.cubicTo(size.width*0.7246732,size.height*0.2135101,size.width*0.7400327,size.height*0.2083333,size.width*0.7532680,size.height*0.2001263);
path_1.cubicTo(size.width*0.7563725,size.height*0.1982323,size.width*0.7609477,size.height*0.1964646,size.width*0.7599673,size.height*0.1925505);
path_1.cubicTo(size.width*0.7589869,size.height*0.1886364,size.width*0.7539216,size.height*0.1878788,size.width*0.7498366,size.height*0.1867424);
path_1.cubicTo(size.width*0.7486928,size.height*0.1864899,size.width*0.7475490,size.height*0.1862374,size.width*0.7464052,size.height*0.1861111);
path_1.cubicTo(size.width*0.7354575,size.height*0.1848485,size.width*0.7246732,size.height*0.1842172,size.width*0.7135621,size.height*0.1849747);
path_1.cubicTo(size.width*0.6928105,size.height*0.1863636,size.width*0.6723856,size.height*0.1881313,size.width*0.6524510,size.height*0.1934343);
path_1.cubicTo(size.width*0.6364379,size.height*0.1976010,size.width*0.6204248,size.height*0.2012626,size.width*0.6057190,size.height*0.2075758);
path_1.cubicTo(size.width*0.6037582,size.height*0.2061869,size.width*0.6032680,size.height*0.2042929,size.width*0.6032680,size.height*0.2022727);
path_1.cubicTo(size.width*0.6122549,size.height*0.1993687,size.width*0.6215686,size.height*0.1968434,size.width*0.6303922,size.height*0.1936869);
path_1.cubicTo(size.width*0.6433007,size.height*0.1888889,size.width*0.6575163,size.height*0.1877525,size.width*0.6709150,size.height*0.1845960);
path_1.cubicTo(size.width*0.6901961,size.height*0.1800505,size.width*0.7098039,size.height*0.1791667,size.width*0.7295752,size.height*0.1789141);
path_1.cubicTo(size.width*0.7364379,size.height*0.1787879,size.width*0.7431373,size.height*0.1800505,size.width*0.7498366,size.height*0.1809343);
path_1.cubicTo(size.width*0.7557190,size.height*0.1816919,size.width*0.7602941,size.height*0.1847222,size.width*0.7640523,size.height*0.1880051);
path_1.cubicTo(size.width*0.7673203,size.height*0.1907828,size.width*0.7674837,size.height*0.1943182,size.width*0.7648693,size.height*0.1976010);
path_1.cubicTo(size.width*0.7622549,size.height*0.2007576,size.width*0.7593137,size.height*0.2040404,size.width*0.7549020,size.height*0.2060606);
path_1.cubicTo(size.width*0.7459150,size.height*0.2101010,size.width*0.7374183,size.height*0.2151515,size.width*0.7276144,size.height*0.2180556);
path_1.cubicTo(size.width*0.7263072,size.height*0.2184343,size.width*0.7245098,size.height*0.2186869,size.width*0.7251634,size.height*0.2202020);
path_1.cubicTo(size.width*0.7258170,size.height*0.2215909,size.width*0.7276144,size.height*0.2208333,size.width*0.7287582,size.height*0.2205808);
path_1.cubicTo(size.width*0.7455882,size.height*0.2176768,size.width*0.7627451,size.height*0.2156566,size.width*0.7799020,size.height*0.2156566);
path_1.cubicTo(size.width*0.7947712,size.height*0.2155303,size.width*0.8096405,size.height*0.2161616,size.width*0.8236928,size.height*0.2203283);
path_1.cubicTo(size.width*0.8387255,size.height*0.2248737,size.width*0.8434641,size.height*0.2315657,size.width*0.8406863,size.height*0.2440657);
path_1.cubicTo(size.width*0.8406863,size.height*0.2443182,size.width*0.8408497,size.height*0.2446970,size.width*0.8408497,size.height*0.2449495);
path_1.cubicTo(size.width*0.8385621,size.height*0.2455808,size.width*0.8377451,size.height*0.2470960,size.width*0.8374183,size.height*0.2487374);
path_1.cubicTo(size.width*0.8297386,size.height*0.2550505,size.width*0.8214052,size.height*0.2604798,size.width*0.8112745,size.height*0.2643939);
path_1.cubicTo(size.width*0.8076797,size.height*0.2657828,size.width*0.8034314,size.height*0.2665404,size.width*0.8001634,size.height*0.2683081);
path_1.cubicTo(size.width*0.7888889,size.height*0.2744949,size.width*0.7750000,size.height*0.2760101,size.width*0.7629085,size.height*0.2805556);
path_1.cubicTo(size.width*0.7580065,size.height*0.2824495,size.width*0.7526144,size.height*0.2835859,size.width*0.7475490,size.height*0.2849747);
path_1.cubicTo(size.width*0.7620915,size.height*0.2872475,size.width*0.7767974,size.height*0.2839646,size.width*0.7906863,size.height*0.2888889);
path_1.cubicTo(size.width*0.7954248,size.height*0.2905303,size.width*0.8011438,size.height*0.2902778,size.width*0.8062092,size.height*0.2912879);
path_1.cubicTo(size.width*0.8155229,size.height*0.2931818,size.width*0.8246732,size.height*0.2958333,size.width*0.8333333,size.height*0.2992424);
path_1.cubicTo(size.width*0.8418301,size.height*0.3025253,size.width*0.8501634,size.height*0.3060606,size.width*0.8560458,size.height*0.3118687);
path_1.cubicTo(size.width*0.8627451,size.height*0.3184343,size.width*0.8647059,size.height*0.3267677,size.width*0.8517974,size.height*0.3323232);
path_1.cubicTo(size.width*0.8408497,size.height*0.3369949,size.width*0.8292484,size.height*0.3391414,size.width*0.8169935,size.height*0.3401515);
path_1.cubicTo(size.width*0.8050654,size.height*0.3411616,size.width*0.7933007,size.height*0.3397727,size.width*0.7812092,size.height*0.3416667);
path_1.cubicTo(size.width*0.7689542,size.height*0.3435606,size.width*0.7560458,size.height*0.3421717,size.width*0.7433007,size.height*0.3441919);
path_1.cubicTo(size.width*0.7300654,size.height*0.3462121,size.width*0.7165033,size.height*0.3467172,size.width*0.7035948,size.height*0.3503788);
path_1.cubicTo(size.width*0.7024510,size.height*0.3507576,size.width*0.7001634,size.height*0.3501263,size.width*0.7003268,size.height*0.3516414);
path_1.cubicTo(size.width*0.7004902,size.height*0.3534091,size.width*0.7027778,size.height*0.3534091,size.width*0.7045752,size.height*0.3532828);
path_1.cubicTo(size.width*0.7066993,size.height*0.3563131,size.width*0.7114379,size.height*0.3549242,size.width*0.7138889,size.height*0.3569444);
path_1.close();
path_1.moveTo(size.width*0.6977124,size.height*0.3010101);
path_1.cubicTo(size.width*0.7045752,size.height*0.2939394,size.width*0.7142157,size.height*0.2902778,size.width*0.7232026,size.height*0.2863636);
path_1.cubicTo(size.width*0.7320261,size.height*0.2825758,size.width*0.7421569,size.height*0.2806818,size.width*0.7516340,size.height*0.2775253);
path_1.cubicTo(size.width*0.7640523,size.height*0.2733586,size.width*0.7772876,size.height*0.2708333,size.width*0.7898693,size.height*0.2665404);
path_1.cubicTo(size.width*0.8013072,size.height*0.2625000,size.width*0.8119281,size.height*0.2578283,size.width*0.8223856,size.height*0.2525253);
path_1.cubicTo(size.width*0.8269608,size.height*0.2502525,size.width*0.8303922,size.height*0.2468434,size.width*0.8333333,size.height*0.2434343);
path_1.cubicTo(size.width*0.8380719,size.height*0.2381313,size.width*0.8361111,size.height*0.2314394,size.width*0.8289216,size.height*0.2281566);
path_1.cubicTo(size.width*0.8194444,size.height*0.2238636,size.width*0.8088235,size.height*0.2222222,size.width*0.7982026,size.height*0.2208333);
path_1.cubicTo(size.width*0.7794118,size.height*0.2183081,size.width*0.7607843,size.height*0.2213384,size.width*0.7423203,size.height*0.2239899);
path_1.cubicTo(size.width*0.7192810,size.height*0.2272727,size.width*0.6978758,size.height*0.2335859,size.width*0.6771242,size.height*0.2419192);
path_1.cubicTo(size.width*0.6656863,size.height*0.2464646,size.width*0.6550654,size.height*0.2518939,size.width*0.6441176,size.height*0.2571970);
path_1.cubicTo(size.width*0.6413399,size.height*0.2584596,size.width*0.6395425,size.height*0.2604798,size.width*0.6369281,size.height*0.2622475);
path_1.cubicTo(size.width*0.6390523,size.height*0.2631313,size.width*0.6405229,size.height*0.2627525,size.width*0.6419935,size.height*0.2625000);
path_1.cubicTo(size.width*0.6498366,size.height*0.2609848,size.width*0.6578431,size.height*0.2607323,size.width*0.6660131,size.height*0.2611111);
path_1.cubicTo(size.width*0.6805556,size.height*0.2618687,size.width*0.6887255,size.height*0.2689394,size.width*0.6862745,size.height*0.2789141);
path_1.cubicTo(size.width*0.6851307,size.height*0.2834596,size.width*0.6816993,size.height*0.2875000,size.width*0.6782680,size.height*0.2912879);
path_1.cubicTo(size.width*0.6656863,size.height*0.3044192,size.width*0.6490196,size.height*0.3140152,size.width*0.6313725,size.height*0.3227273);
path_1.cubicTo(size.width*0.6279412,size.height*0.3243687,size.width*0.6253268,size.height*0.3263889,size.width*0.6212418,size.height*0.3289141);
path_1.cubicTo(size.width*0.6295752,size.height*0.3292929,size.width*0.6369281,size.height*0.3290404,size.width*0.6442810,size.height*0.3301768);
path_1.cubicTo(size.width*0.6598039,size.height*0.3325758,size.width*0.6715686,size.height*0.3412879,size.width*0.6696078,size.height*0.3521465);
path_1.cubicTo(size.width*0.6684641,size.height*0.3582071,size.width*0.6643791,size.height*0.3630051,size.width*0.6593137,size.height*0.3670455);
path_1.cubicTo(size.width*0.6478758,size.height*0.3758838,size.width*0.6331699,size.height*0.3806818,size.width*0.6181373,size.height*0.3842172);
path_1.cubicTo(size.width*0.6022876,size.height*0.3880051,size.width*0.5859477,size.height*0.3895202,size.width*0.5694444,size.height*0.3898990);
path_1.cubicTo(size.width*0.5648693,size.height*0.3900253,size.width*0.5622549,size.height*0.3904040,size.width*0.5650327,size.height*0.3946970);
path_1.cubicTo(size.width*0.5679739,size.height*0.3992424,size.width*0.5673203,size.height*0.4040404,size.width*0.5645425,size.height*0.4087121);
path_1.cubicTo(size.width*0.5593137,size.height*0.4172980,size.width*0.5498366,size.height*0.4215909,size.width*0.5385621,size.height*0.4234848);
path_1.cubicTo(size.width*0.5336601,size.height*0.4243687,size.width*0.5285948,size.height*0.4243687,size.width*0.5230392,size.height*0.4248737);
path_1.cubicTo(size.width*0.5413399,size.height*0.4340909,size.width*0.5617647,size.height*0.4373737,size.width*0.5820261,size.height*0.4402778);
path_1.cubicTo(size.width*0.5923203,size.height*0.4417929,size.width*0.6029412,size.height*0.4409091,size.width*0.6133987,size.height*0.4382576);
path_1.cubicTo(size.width*0.6297386,size.height*0.4339646,size.width*0.6348039,size.height*0.4250000,size.width*0.6264706,size.height*0.4133838);
path_1.cubicTo(size.width*0.6217320,size.height*0.4066919,size.width*0.6153595,size.height*0.4008838,size.width*0.6081699,size.height*0.3958333);
path_1.cubicTo(size.width*0.6065359,size.height*0.3946970,size.width*0.6040850,size.height*0.3938131,size.width*0.6042484,size.height*0.3916667);
path_1.cubicTo(size.width*0.6066993,size.height*0.3906566,size.width*0.6075163,size.height*0.3926768,size.width*0.6093137,size.height*0.3929293);
path_1.cubicTo(size.width*0.6274510,size.height*0.3953283,size.width*0.6454248,size.height*0.3983586,size.width*0.6629085,size.height*0.4031566);
path_1.cubicTo(size.width*0.6728758,size.height*0.4059343,size.width*0.6834967,size.height*0.4071970,size.width*0.6936275,size.height*0.4099747);
path_1.cubicTo(size.width*0.7142157,size.height*0.4155303,size.width*0.7351307,size.height*0.4179293,size.width*0.7566993,size.height*0.4161616);
path_1.cubicTo(size.width*0.7638889,size.height*0.4155303,size.width*0.7712418,size.height*0.4141414,size.width*0.7732026,size.height*0.4073232);
path_1.cubicTo(size.width*0.7745098,size.height*0.4029040,size.width*0.7722222,size.height*0.3991162,size.width*0.7696078,size.height*0.3954545);
path_1.cubicTo(size.width*0.7619281,size.height*0.3845960,size.width*0.7495098,size.height*0.3773990,size.width*0.7364379,size.height*0.3713384);
path_1.cubicTo(size.width*0.7210784,size.height*0.3641414,size.width*0.7044118,size.height*0.3584596,size.width*0.6864379,size.height*0.3560606);
path_1.cubicTo(size.width*0.6830065,size.height*0.3555556,size.width*0.6802288,size.height*0.3546717,size.width*0.6774510,size.height*0.3526515);
path_1.cubicTo(size.width*0.7006536,size.height*0.3452020,size.width*0.7240196,size.height*0.3396465,size.width*0.7488562,size.height*0.3380051);
path_1.cubicTo(size.width*0.7727124,size.height*0.3363636,size.width*0.7968954,size.height*0.3383838,size.width*0.8205882,size.height*0.3345960);
path_1.cubicTo(size.width*0.8303922,size.height*0.3329545,size.width*0.8405229,size.height*0.3324495,size.width*0.8495098,size.height*0.3286616);
path_1.cubicTo(size.width*0.8540850,size.height*0.3267677,size.width*0.8560458,size.height*0.3237374,size.width*0.8544118,size.height*0.3202020);
path_1.cubicTo(size.width*0.8532680,size.height*0.3176768,size.width*0.8513072,size.height*0.3154040,size.width*0.8483660,size.height*0.3135101);
path_1.cubicTo(size.width*0.8344771,size.height*0.3041667,size.width*0.8173203,size.height*0.3001263,size.width*0.8001634,size.height*0.2964646);
path_1.cubicTo(size.width*0.7808824,size.height*0.2924242,size.width*0.7609477,size.height*0.2914141,size.width*0.7410131,size.height*0.2934343);
path_1.cubicTo(size.width*0.7312092,size.height*0.2944444,size.width*0.7212418,size.height*0.2952020,size.width*0.7120915,size.height*0.2989899);
path_1.cubicTo(size.width*0.7076797,size.height*0.2998737,size.width*0.7031046,size.height*0.3012626,size.width*0.6977124,size.height*0.3010101);
path_1.close();
path_1.moveTo(size.width*0.5959150,size.height*0.6977273);
path_1.cubicTo(size.width*0.5967320,size.height*0.6873737,size.width*0.5952614,size.height*0.6747475,size.width*0.5929739,size.height*0.6623737);
path_1.cubicTo(size.width*0.5885621,size.height*0.6376263,size.width*0.5812092,size.height*0.6133838,size.width*0.5705882,size.height*0.5897727);
path_1.cubicTo(size.width*0.5645425,size.height*0.5762626,size.width*0.5568627,size.height*0.5632576,size.width*0.5503268,size.height*0.5500000);
path_1.cubicTo(size.width*0.5486928,size.height*0.5468434,size.width*0.5465686,size.height*0.5462121,size.width*0.5426471,size.height*0.5483586);
path_1.cubicTo(size.width*0.5351307,size.height*0.5523990,size.width*0.5271242,size.height*0.5560606,size.width*0.5179739,size.height*0.5575758);
path_1.cubicTo(size.width*0.5133987,size.height*0.5583333,size.width*0.5135621,size.height*0.5601010,size.width*0.5148693,size.height*0.5625000);
path_1.cubicTo(size.width*0.5223856,size.height*0.5762626,size.width*0.5284314,size.height*0.5902778,size.width*0.5334967,size.height*0.6046717);
path_1.cubicTo(size.width*0.5410131,size.height*0.6262626,size.width*0.5454248,size.height*0.6483586,size.width*0.5465686,size.height*0.6705808);
path_1.cubicTo(size.width*0.5473856,size.height*0.6875000,size.width*0.5462418,size.height*0.7042929,size.width*0.5433007,size.height*0.7212121);
path_1.cubicTo(size.width*0.5397059,size.height*0.7420455,size.width*0.5333333,size.height*0.7622475,size.width*0.5248366,size.height*0.7821970);
path_1.cubicTo(size.width*0.5232026,size.height*0.7858586,size.width*0.5207516,size.height*0.7893939,size.width*0.5204248,size.height*0.7933081);
path_1.cubicTo(size.width*0.5197712,size.height*0.8011364,size.width*0.5191176,size.height*0.8090909,size.width*0.5178105,size.height*0.8169192);
path_1.cubicTo(size.width*0.5174837,size.height*0.8193182,size.width*0.5186275,size.height*0.8204545,size.width*0.5220588,size.height*0.8208333);
path_1.cubicTo(size.width*0.5344771,size.height*0.8220960,size.width*0.5468954,size.height*0.8217172,size.width*0.5593137,size.height*0.8208333);
path_1.cubicTo(size.width*0.5620915,size.height*0.8207071,size.width*0.5632353,size.height*0.8194444,size.width*0.5640523,size.height*0.8178030);
path_1.cubicTo(size.width*0.5707516,size.height*0.8046717,size.width*0.5772876,size.height*0.7916667,size.width*0.5821895,size.height*0.7780303);
path_1.cubicTo(size.width*0.5913399,size.height*0.7523990,size.width*0.5960784,size.height*0.7265152,size.width*0.5959150,size.height*0.6977273);
path_1.close();
path_1.moveTo(size.width*0.5230392,size.height*0.7681818);
path_1.cubicTo(size.width*0.5240196,size.height*0.7665404,size.width*0.5251634,size.height*0.7654040,size.width*0.5256536,size.height*0.7641414);
path_1.cubicTo(size.width*0.5334967,size.height*0.7411616,size.width*0.5388889,size.height*0.7178030,size.width*0.5401961,size.height*0.6940657);
path_1.cubicTo(size.width*0.5416667,size.height*0.6688131,size.width*0.5383987,size.height*0.6439394,size.width*0.5312092,size.height*0.6191919);
path_1.cubicTo(size.width*0.5254902,size.height*0.5994949,size.width*0.5179739,size.height*0.5803030,size.width*0.5071895,size.height*0.5619949);
path_1.cubicTo(size.width*0.5063725,size.height*0.5606061,size.width*0.5060458,size.height*0.5594697,size.width*0.5035948,size.height*0.5597222);
path_1.cubicTo(size.width*0.4995098,size.height*0.5601010,size.width*0.4954248,size.height*0.5603535,size.width*0.4915033,size.height*0.5617424);
path_1.cubicTo(size.width*0.4885621,size.height*0.5627525,size.width*0.4882353,size.height*0.5637626,size.width*0.4893791,size.height*0.5659091);
path_1.cubicTo(size.width*0.4936275,size.height*0.5746212,size.width*0.4968954,size.height*0.5835859,size.width*0.5001634,size.height*0.5924242);
path_1.cubicTo(size.width*0.5124183,size.height*0.6253788,size.width*0.5179739,size.height*0.6592172,size.width*0.5209150,size.height*0.6933081);
path_1.cubicTo(size.width*0.5230392,size.height*0.7170455,size.width*0.5236928,size.height*0.7407828,size.width*0.5215686,size.height*0.7645202);
path_1.cubicTo(size.width*0.5214052,size.height*0.7656566,size.width*0.5214052,size.height*0.7669192,size.width*0.5230392,size.height*0.7681818);
path_1.close();
path_1.moveTo(size.width*0.6352941,size.height*0.2631313);
path_1.lineTo(size.width*0.6351307,size.height*0.2632576);
path_1.lineTo(size.width*0.6354575,size.height*0.2632576);
path_1.lineTo(size.width*0.6352941,size.height*0.2631313);
path_1.close();
Paint paint_1_fill = Paint()..style=PaintingStyle.fill;
paint_1_fill.color = color;
canvas.drawPath(path_1,paint_1_fill);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
everything is good, I send the color and it draws well,
return Stack(
children: <Widget>[
CustomPaint(
painter: PathUno(Color(0xff000000)),
child: SizedBox(
width: MediaQuery.of(context).size.width, height: 400)),
CustomPaint(
painter: PathDos(Color(0xffffffff)),
child: SizedBox(
width: MediaQuery.of(context).size.width, height: 400)),
],
);
but I need to know how can I set a GestureDetector in the right way, because when I put it, any part of the screen gave me that ontap, the idea is: when the user touch that class or path change color,
Thank you!
If you want the gesture to only react to gestures on the filled part of the custom paint, you need to override hitTest on your CustomPainter classes:
Path? _path;
#override
void paint(Canvas canvas, Size size) {
Path path_1 = Path();
//...
_path = path_1;
}
#override
bool? hitTest(Offset offset) {
return _path?.contains(offset) ?? false;
}
Here's a dartpad showing it in action. Also see this previous thread on the same question.

How can I clip ImageFilter or ColorFilter in Flutter

I want to clip ImageFilter or ColorFilter.
When I added ClipPath widget to filter widgets as a parent, it applied clipping to filter widget's child too.
I tried to make custom widget, copied ImageFilter code and added clipping to paint function. It worked but only on Image and not-editable Text widgets, any other widget just ignores first paint call.
#override
void paint(PaintingContext context, Offset offset) {
context.clipPathAndPaint(
InvertedPrintHoleClipper().getClip(size),
Clip.hardEdge,
context.estimatedBounds,
() {
context.pushClipPath(
true,
offset,
context.estimatedBounds,
InvertedPrintHoleClipper().getClip(size),
paintFilteredLayer,
);
},
);
context.clipRectAndPaint(
Rect.fromCenter(
center: size.center(Offset.zero),
width: size.width / 2,
height: size.height / 2,
),
Clip.hardEdge,
context.estimatedBounds,
() {
context.pushClipRect(
true,
offset,
PrintHoleClipper().getClip(size),
super.paint,
);
},
);
}
void paintFilteredLayer(PaintingContext context, Offset offset) {
if (layer == null) {
layer = ImageFilterLayer(imageFilter: imageFilter);
} else {
final ImageFilterLayer filterLayer = layer! as ImageFilterLayer;
filterLayer.imageFilter = imageFilter;
}
context.pushLayer(layer!, super.paint, offset);
}
Sorry for my English

Flutter how to create parallax effect for background image

I am trying to create a parallax effect for the background image of a container.
I followed this tutorial https://docs.flutter.dev/cookbook/effects/parallax-scrolling.
However I would like for the background image to remain still in the viewport ad the user scrolls.
Basically I would like to achieve this behavior https://www.w3schools.com/howto/tryhow_css_parallax_demo.htm.
I believe that in order to achieve this I have to modify the paintChildren method inside ParallaxFlowDelegate
#override
void paintChildren(FlowPaintingContext context) {
// Calculate the position of this list item within the viewport.
final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
final listItemBox = listItemContext.findRenderObject() as RenderBox;
final listItemOffset = listItemBox.localToGlobal(
listItemBox.size.centerLeft(Offset.zero),
ancestor: scrollableBox);
// Determine the percent position of this list item within the
// scrollable area.
final viewportDimension = scrollable.position.viewportDimension;
final scrollFraction =
(listItemOffset.dy / viewportDimension).clamp(0.0, 1.0);
// Convert the background alignment into a pixel offset for
// painting purposes.
final backgroundSize =
(backgroundImageKey.currentContext!.findRenderObject() as RenderBox)
.size;
// Calculate the vertical alignment of the background
// based on the scroll percent.
final verticalAlignment = Alignment(0.0, scrollFraction * 2 - 1);
final listItemSize = context.size;
final childRect =
verticalAlignment.inscribe(backgroundSize, Offset.zero & listItemSize);
// Paint the background.
context.paintChild(
0,
transform:
Transform.translate(offset: Offset(0.0, childRect.top)).transform,
);
}
but I can't figure out how.
Any help would be greatly appreciated :)
I was just messing, of course I can figure it out.
For anyone interested simply follow the flutter dev tutorial https://docs.flutter.dev/cookbook/effects/parallax-scrolling but replace their ParallaxFlowDelegate class with the following:
import 'package:flutter/material.dart';
class ParallaxFlowDelegate extends FlowDelegate {
final ScrollableState scrollable;
final BuildContext listItemContext;
final GlobalKey backgroundImageKey;
ParallaxFlowDelegate({
required this.scrollable,
required this.listItemContext,
required this.backgroundImageKey,
}) : super(repaint: scrollable.position);
#override
BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) {
return BoxConstraints.expand(
width: constraints.maxWidth,
height: scrollable.position.viewportDimension
);
}
#override
void paintChildren(FlowPaintingContext context) {
// Calculate the position of this list item within the viewport.
final scrollableBox = scrollable.context.findRenderObject() as RenderBox;
final listItemBox = listItemContext.findRenderObject() as RenderBox;
final listItemSize = context.size;
//Gets the offset of the top of the list item from the top of the viewport
final listItemOffset = listItemBox.localToGlobal(
listItemBox.size.topCenter(Offset.zero),
ancestor: scrollableBox);
// Get the size of the background image
final backgroundSize =
(backgroundImageKey.currentContext!.findRenderObject() as RenderBox)
.size;
//Gets the vertical size of the viewport (excludes appbars)
final viewportDimension = scrollable.position.viewportDimension;
// Determine the percent position of this list item within the
// scrollable area.
// - scrollFraction is 1 if listItem's top edge is at the bottom of the
// viewport.
// - scrollFraction is 0 if listItem's top edge is at the top of the
// viewport
// - scrollFraction is -1 if listItem's bottom edge is at the top of the
// viewport
final double scrollFraction, yOffset;
if(listItemOffset.dy > 0){
scrollFraction = (listItemOffset.dy / viewportDimension).clamp(0, 1.0);
yOffset = -scrollFraction * backgroundSize.height;
}else{
scrollFraction = (listItemOffset.dy / listItemSize.height).clamp(-1, 0);
yOffset = -scrollFraction * listItemSize.height;
}
// Paint the background.
context.paintChild(
0,
transform:
Transform.translate(offset: Offset(0, yOffset)).transform,
);
}
#override
bool shouldRepaint(ParallaxFlowDelegate oldDelegate) {
return scrollable != oldDelegate.scrollable ||
listItemContext != oldDelegate.listItemContext ||
backgroundImageKey != oldDelegate.backgroundImageKey;
}
}
Works like a beauty for vertically scrolling pages :)

Flutter: Print image with right orientation and size A4

I want to print an image in flutter. I use the package "printing 3.5.0". My problem is now I want use the hole space of the page. But when I put the orientation or size, both parameters are ignored.
_printImage(GlobalKey globalKey) async {
final pdf = new PdfDocument();
final page = new PdfPage(pdf, pageFormat: PdfPageFormat.a4);
final doc = pw.Document();
final g = page.getGraphics();
RenderRepaintBoundary boundary =
globalKey.currentContext.findRenderObject();
ui.Image _image = await boundary.toImage();
var bytes = await _image.toByteData(format: ui.ImageByteFormat.rawRgba);
PdfImage image = new PdfImage(pdf,
image: bytes.buffer.asUint8List(),
width: _image.width,
height: _image.height);
doc.addPage(pw.Page(build: (pw.Context context) {
return pw.Center(
child: pw.Image(image),
); // Center
}));
g.drawImage(image, 20.0, 0.0);
Printing.layoutPdf(onLayout: (pageFormat) {
return pdf.save();
});
}
Even if I adjust the width and height of the image, the whole page is not used.
Does not exist a parameter that automatically scales the image on the whole page and observes the orientation?
I'm grateful for any help.

Flutter Transform translate a widget from current position to another position

If I want to translate any Widget in my flutter app, I will use below code.
Transform.translate()
Translate function required Offset (dx,dy). But I want to find dx or dy value of the current widget so I can slightly move widget to left and right or top and bottom from the current position on device.
That's how it works
If I do
Transform.translate(offset: Offset(-10, 20)
It's transform its position 10 to the left and 20 down from its normal render position.
It's not so easy to do. You have to work with render objects. You can copy-paste Transform and RenderTransform classes to begin with. RenderTransform has overridden method paint and its argument offset is widget's local position:
#override
void paint(PaintingContext context, Offset offset) {
if (child != null) {
final Matrix4 transform = _effectiveTransform;
final Offset childOffset = MatrixUtils.getAsTranslation(transform);
if (childOffset == null) {
layer = context.pushTransform(needsCompositing, offset, transform, super.paint, oldLayer: layer);
} else {
super.paint(context, offset + childOffset);
layer = null;
}
}
}
For example, I'll move the widget to 0 position on X, if its X position is less than 20:
if (child != null) {
final Matrix4 transform = _effectiveTransform;
Offset childOffset;
// Move it to the edge, if X position is less than 20
if (offset.dx < 20) {
childOffset = Offset(-offset.dx, 0);
} else {
childOffset = MatrixUtils.getAsTranslation(transform);
}
if (childOffset == null) {
...
And then I'll add 10 pixels padding from left in parent's widget, but the widget will stick to the left side:
Container(
padding: EdgeInsets.only(top: 20, left: 10),
child: MyTransform.translate(
offset: Offset.zero,
child: Container(
width: 100,
height: 100,
color: Colors.red
)
),
),