Flutter issue 5 custom widget

When it comes to custom controls, it's no stranger to those who have done iOS and Android development. flutter also provides relevant APIs. All kinds of widgets provided by ZTE in fluent can meet most of the business requirements. Through different combinations, we can also achieve some more complex requirements. Today we will talk about a custom widget that needs to be drawn by ourselves. In Android, we draw through the api of drawing paint canvas and other columns of custom view, and canvas is also provided in fluent.

class TestPainter extends CustomPainter{

  @override
  void paint(Canvas canvas, Size size) {
    // TODO: implement paint
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return oldDelegate != this;
  }

}

Let's customize a Painter first. You can see that the Painter inherits the CustomPainter. We need to implement two methods. paint is equivalent to ondraw in Android, but there is an additional size parameter in the parameter.

Parameter size

We see that size provides several construction methods, the most important of which are width and height. This is equivalent to our onmeasure method of customizing view in android. You can see that the size in the fluent is more flexible.

Parameter canvas

Those who have written android custom view are more familiar with this api. Yes, most APIs are the same.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

Let's write a demo. Let's take a look at the renderings:

This is a standard regular hexagon. Let's split it up now,

  • Hexagon
  • Internal grid
  • External circle
  • 6 corner text
  • animation

Start rolling code ~

  1. Create widget
  2. Create custom painter
  3. Add drawing algorithm

1. Create widget

2. Create a custom painter and initialize it

3. Drawing method

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

Complete code

import 'dart:core';
import 'dart:ui' as ui;
import 'dart:ui';
import 'dart:math';
import 'package:flutter/material.dart';

class PageTest2 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new PageTest2State();
  }
}

class PageTest2State extends State with SingleTickerProviderStateMixin {
  List<double> _ranks = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
  AnimationController _controller;
  Animation _curve;

  @override
  void initState() {
    _controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
    _curve = new CurvedAnimation(parent: _controller, curve: Curves.fastLinearToSlowEaseIn);
    _curve.addListener(() {
      setState(() {});
    });
    _controller.forward();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _ranks = generateRanks();
          _controller.reset();
          _controller.forward();
        },
        child: Text("Press"),
      ),
      body: Container(
        constraints: BoxConstraints(
          minWidth: double.infinity,
          minHeight: double.infinity,
        ),
        child: Center(
          child: Container(
            constraints: BoxConstraints(
              minWidth: 200,
              minHeight: 200,
            ),
            child: CustomPaint(
              painter: TestPainter(_curve.value, _ranks),
            ),
          ),
        ),
      ),
    );
  }

  List<double> generateRanks() {
    List<double> ranks = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
    for (int i = 0; i < ranks.length; i++) {
      ranks[i] = Random().nextDouble() * 100;
    }
    return ranks;
  }
}

class TestPainter extends CustomPainter {
  ​​double _process;// Animation progress
  Paint _polygonPaint;// A brush for drawing hexagon
  Paint _frameStrokePaint;// A brush for drawing hexagonal meshes
  Paint _rankPaint;// Paint center level brushes
  double _centerX;// Custom TestPainter center x
  double _centerY;// Custom TestPainter Center
  double _sideLength;// Regular hexagon side length
  double _centerCircleRadius;// Radius of central circle
  List<double> _ranks;// Hierarchical data
  List<String> _labelString = const ["physical strength", "spirit", "Physics", "magic", "defense", "money"];

  TestPainter(this._process, this._ranks) {
    _polygonPaint = new Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill //Fill
      ..color = Color(Colors.blueGrey.value);

    _frameStrokePaint = new Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.stroke //Stroke
      ..color = Color(Colors.green.value);

    _rankPaint = new Paint()
      ..isAntiAlias = true
      ..style = PaintingStyle.fill //Fill
      ..color = Color(Colors.red.withAlpha(130).value);

    _sideLength = 120;
    _centerCircleRadius = 120;
  }

  @override
  void paint(Canvas canvas, Size size) {
    _centerX = size.width / 2.0;
    _centerY = size.height / 2.0;

    _drawPolygon(canvas, _sideLength);
    _drawPolygonFrame(canvas, _sideLength, 4);
    _drawCircle(canvas);
    _drawRank(canvas, _sideLength, _ranks);
    _drawText(canvas, _sideLength);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
  // Draw text
  void _drawText(Canvas canvas, double slidLength) {
    for (int i = 0; i < _labelString.length; i++) {
      String label = _labelString[i] + "+" + (_ranks[i] * _process).toStringAsFixed(1);
      TextSpan span = new TextSpan(
        style: TextStyle(color: Colors.black),
        text: label,
      );
      TextPainter tp = new TextPainter(
          text: span,
          textAlign: TextAlign.center,
          textDirection: TextDirection.ltr);
      tp.layout();
      double endX = (_centerX + slidLength * sin(pi / 3 * i));
      double endY = (_centerY - slidLength * cos(pi / 3 * i));
      if (i == 0) {
        endX = endX - tp.width / 2;
        endY = endY - tp.height;
      } else if (i == 1) {
        endX = endX;
        endY = endY - tp.height / 2;
      } else if (i == 2) {
        endX = endX;
        endY = endY - tp.height / 2;
      } else if (i == 3) {
        endX = endX - tp.width / 2;
      } else if (i == 4) {
        endX = endX - tp.width;
        endY = endY - tp.height / 2;
      } else {
        endX = endX - tp.width;
        endY = endY - tp.height / 2;
      }
      tp.paint(canvas, new Offset(endX, endY));
    }
  }
  // Draw circles
  void _drawCircle(Canvas canvas){
    canvas.drawCircle(Offset(_centerX, _centerY), _centerCircleRadius, _frameStrokePaint);
  }
  // Draw center level
  void _drawRank(Canvas canvas, double slidLength, List<double> ranks) {
    Path path = new Path();
    double percentLength = slidLength / 100 * _process;
    path.moveTo(_centerX, _centerY - ranks[0] * percentLength); //Initial coordinates
    for (int i = 0; i < 6; i++) {
      double rankRadius = ranks[i] * percentLength;
      double endX = (_centerX + rankRadius * sin(pi / 3 * i));
      double endY = (_centerY - rankRadius * cos(pi / 3 * i));
      path.lineTo(endX, endY);
    }
    path.close();
    canvas.drawPath(path, _rankPaint);
  }
  // Draw a central hexagon mesh
  void _drawPolygonFrame(Canvas canvas, double slidLength, int row) {
    for (int k = 1; k <= row; k++) {
      double tempSlideLength = slidLength / row * k;
      Path path = new Path();
      path.moveTo(_centerX, _centerY - tempSlideLength);
      for (int i = 0; i < 6; i++) {
        double endX = (_centerX + tempSlideLength * sin(pi / 3 * i));
        double endY = (_centerY - tempSlideLength * cos(pi / 3 * i));
        path.lineTo(endX, endY);
        canvas.drawLine(
            Offset(_centerX, _centerY), Offset(endX, endY), _frameStrokePaint);
      }
      path.close();
      canvas.drawPath(path, _frameStrokePaint);
    }
  }
  // Draw hexagon base
  void _drawPolygon(Canvas canvas, double slidLength) {
    Path path = new Path();
    path.moveTo(_centerX, _centerY - slidLength);
    for (int i = 0; i < 6; i++) {
      double endX = (_centerX + slidLength * sin(pi / 3 * i));
      double endY = (_centerY - slidLength * cos(pi / 3 * i));
      path.lineTo(endX, endY);
    }
    path.close();
    canvas.drawPath(path, _polygonPaint);
  }
}

 

 

 

 

 

 

Published 4 original articles, won praise 0, visited 73
Private letter follow

Tags: Android iOS

Posted on Wed, 15 Jan 2020 00:39:10 -0800 by sysgenmedia