Introduction to the
After the function is implemented, complete the incomplete but relatively valuable learning DEMO:
Flutter – a price range filter modeled after Airbnb. (a)
Flutter – a price range filter modeled after Airbnb. (2)
Plotting Bezier curves with Flutter-CustomPaint
The page layout
As before, I always put the introduction in comments so it’s easy to connect to the code without confusing the reader.
There are two main parts:
1. CustomPaint(), with which we can draw a diagram, has three parameters to note.
They are: Painter, child, groundPainter
Painter, Child, groundPainter will cover the former
RangeSlider, used to refresh the left and right values to demonstrate path interception
Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ CustomPaint( size: //foregroundPainter: buildPainter(), //foregroundPainter: buildPainter(), //foregroundPainter: Container( // width: size.width, // height: size.height, // color: Colors.white, // ), ), SizedBox( height: D, values: RangeValues(leftValue,rightValue), and the divisions: 100, min: 0.0, Max: 1.0, onChanged: (values){ debugPrint("range value : $values");
leftValue = values.start;
rightValue = values.end;
setState(() { }); }) ",Copy the code
CustomPaint is the main part, and you can draw anything by passing in a Painter, so let’s show what buildPainter() initializes:
ChartPainter buildPainterVar dataList = [ChartBean(x:"\ $2000", y: 32),
ChartBean(x: "\ $1100", y: 48),
ChartBean(x: "\ $1400", y: 32),
ChartBean(x: "\ $500", y: 24),
ChartBean(x: "\ $800", y: 50),
ChartBean(x: "\ $1800", y: 25),
ChartBean(x: "\ $1200", y: 18),
ChartBean(x: "\ $2000", y: 32),
ChartBean(x: "\ $1100", y: 48),
ChartBean(x: "\ $1400", y: 32),
];
returnChartPainter(// The default values are 0-1 leftStart: leftValue,rightEnd: rightValue, chartBeans: dataList, lineColor: Colors. BlueAccent,// line Colors // chart fillColors: [Colors. Orange. WithOpacity (0.8), Colors, orangeAccent. WithOpacity (0.5)], lineWith: 3, / / y scale quantity yAxisNum: dataList.length ); }Copy the code
The custom Painter
ChartPainter is our own Painter, which inherits from CustomPainter and needs to implement two methods:
ShouldRepaint (ChartPainter oldDelegate)
We can take our own variable values based on the parameters, and then decide whether to redraw as needed (e.g., add a flag, cut left and right value changes, animation progress, etc.)
2. Paint (Canvas Canvas, Size Size). This is the Size given by the Canvas and parent widget, which is also the main implementation area
@override void paint(Canvas canvas, Size size) { _init(size); // initialize _drawLine(canvas, size); // draw a curve}Copy the code
The Path is generated
MinMax (List<double>) initBorder(Size); minMax (List<double>) initBorder(Size); initPath(size); // Initialize path}Copy the code
The initPath () method is used to calculate and generate the path of the curve:
Notice that start X,Y, and end X,Y are bottom left and top right, respectively.
void initPath(Size size) {
if (path == null) {
if(chartBeans ! = null && chartBeans.length > 0 && minMax[0] > 0) { path = Path(); Double preX,// the x value of the previous data preY,// the y value of the previous data currentX, currentY; int length = chartBeans.length; Double W = _fixedWidth/(length-1); double W = _fixedWidth/(length-1);for (int i = 0; i < length; i++) {
if(i == 0) { var key = startX; // chartBeans[I]. Y/maxMinVar value = (starty-chartbeans [I]. Y/minMax[0] *); // Starty-chartbeans [I] _fixedHeight); // moveTo the position of the corresponding data path.moveto (key, value);continue; } // After drawing the first point, pan it to the right by a width (w) currentX = startX + w * I; PreX = startX + W * (i-1); PreY = (starty-Chartbeans [i-1]. Y/minMax[0] * _fixedHeight); currentY = (startY - chartBeans[i].y / minMax[0] * _fixedHeight); // Draw the Bessel path (you can search this site or Baidu, // Control point 1 (preX + currentX) / 2, // Control point 1 (preX + currentX) / 2, // Control point 1 (preX + currentX) / 2, // // control point 2 currentX, currentY); // If you use a line, you can directly. }}}}Copy the code
The curve path that supports generating data from dataList is now complete
Draw the Path
Use the _drawLine(canvas, size) method to draw based on the generated path as follows:
_drawLine(Canvas canvas, Size size) {
if (chartBeans == null || chartBeans.length == 0) return; var paint = Paint() .. isAntiAlias =true// Anti-aliasing.. strokeWidth = lineWith .. StrokeCap = strokecap. round// This is the style after the brush is finished: here is the circle.. color = lineColor .. style = PaintingStyle.stroke; // Android native can obtain the coordinates of each point of the path according to PathMeasure /// Flutter is computeMetrics, and the function of flutter is basically the same.if (minMax[0] <= 0) return;
var pathMetrics = path.computeMetrics(forceClosed: false); Var list = pathmetrics.tolist (); var list = pathmetrics.tolist (); var list = pathmetrics.tolist (); Var length = list.length.toint () - (list.length.toint () * leftStart) - var length = list.length.toint () - (list.length.toInt() * (1-rightEnd)); Path linePath = new Path(); // Fill the color area Path shadowPath = new Path();for(int i = 0; i < length; Double startExtr = list[I]. Length * (leftStart); Double endExtr = list[I]. Length * (rightEnd); var extractPath = list[i].extractPath(startExtr, endExtr , startWithMoveTo:true); //extractPath.getBounds() linePath.addPath(extractPath, Offset(0, 0)); shadowPath = extractPath; } / / / add shaders to brush, can through a variety of gradient createShader () method to generate shader / / / here is using a linear gradient, and RadialGradient, SweepGradientif(fillColors ! = null) { var shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, tileMode: TileMode.clamp, colors: fillColors) .createShader(Rect.fromLTRB(startX, endY, startX, startY)); /// connect the last point of the path to the starting point, forming a closed loop shadowPath.. lineTo(startX + (_fixedWidth * rightEnd) , startY) .. lineTo((startX+ (endX * leftStart ) ), startY) .. close(); // Draw the shadow canvas.. drawPath( shadowPath, new Paint() .. shader = shader .. isAntiAlias =true
..style = PaintingStyle.fill);
}
//再画曲线,目的是防止阴影覆盖曲线
canvas.drawPath(linePath, paint);
}
Copy the code
End & DEMO
We pass variables left and right to Painter, and then adjust these two variables through range Slider and refresh. We have achieved the effect of intercepting the path. You can run the DEMO.
Github.com/bladeofgod/…
PS: We can also pass in the click position, and use this to do more interactive functions on the top. This will be implemented later.
🙂 thank you