话不多说,先上图
先说下大概思路:
1,根据半径画最外圈的最浅色的那个背景,然后半径一次减少,画颜色比较深的背景+
(1)先计算渐变色背景的各个点的坐标,公式:x = R * cos(角度 - Π/2),y = R * sin(角度 - Π/2),这里减Π/2是为了符合x,y坐标的变化规律,因为原点是取在图形中心
(2)再使用paint画出各个颜色的背景,记得save和restore一下,保存画的效果(这里如果是用安卓的话,会有UI过度绘制的问题,按理说应该要每块区域每块区域地画,但是那样计算量太大了,于是放弃)
2,利用上面计算出来的最外圈的一组点坐标,将中间的分割白线画好,如果渐变色背景画在白线前,会出现白线被覆盖的情况,所以要注意绘图顺序
3,使用公式:x = (R +d)* cos(角度 - Π/2),y = (R +d) * sin(角度 - Π/2)计算出文字距离中心的距离,其中d为自己调节的值,想文字远一点就大一点,否则小一点,即为这一段,上面两个map是求出能力值的点坐标,下面两个是求出文字点的坐标,具体距离中心要多少距离,自己将代码中的60和50根据需要自己调节即可,这里在i=0的情况下是因为这两组点的坐标只需要计算一次
(1)计算
(2)画出文字,这里注意一下,文字是根据你计算的点作为文字左上角开始绘制,所以在绘制的时候,Offset的x坐标要根据pc的宽度进行减少一半以便文字居中,y坐标可以根据实际情况进行微调
4,计算出能力值线条的各个点坐标,进行绘制
(1)使用公式,x = (能力值/100)* (R +d)*cos(角度 - Π/2),y = (能力值/100)* (R +d) * sin(角度 - Π/2), 计算出能力值线条的各个点坐标
(2)绘制能力值线条,记得在path确定好后要close一下,这样是为了将最后一个点和第一个点进行连接
5,最后在view中进行调用即可,第一个参数是渐变色背景板半径,第二个数组是各能力的数值,第三个数组是各能力的名称,这两个数组的长度一定要是一样的!!!想要增加能力的种类,只需要在数组里面各加上对应的值即可。
这里map是可以用list代替的,写完了就懒得改了,反正调用写法都一样(→_→)
最后附上源码,如有不对,希望不吝赐教,
PS:如果有帮助,打个赏呗...XD
import 'dart:ui';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'dart:math';
class AbilityView extends CustomPainter{
final List<int> _ab;//各能力的数值list,100为满分
final double _r;//最外圈的半径
final List<String> _abName;//能力名称list
AbilityView(this._r, this._ab, this._abName);
@override
void paint(Canvas canvas, Size size) {
_paintBack(canvas,size);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
void _paintBack(Canvas canvas,Size size) {
canvas.translate(size.width/2, size.height/2 + 15);//移动到图中心,纵坐标根据需求微调
var _angle = pi * 2 / _ab.length;
List<Color> _colorList = [Color.fromARGB(255, 235, 235, 235),Color.fromARGB(255, 218, 215, 217),Color.fromARGB(255, 189, 176, 185),Color.fromARGB(255, 167, 144, 159),Color.fromARGB(255, 148, 120, 138),Color.fromARGB(255, 122, 90, 111),Color.fromARGB(255, 111, 77, 99)];
List<Map<int,double>> _xPointList = [];//每层的各个点x坐标
List<Map<int,double>> _yPointList = [];//每层的各个点y坐标
Map<int,double> _xPointMap = {};//int--能力值索引,double--能力值x坐标
Map<int,double> _yPointMap = {};//int--能力值索引,double--能力值y坐标
Map<int,double> _xTextMap = {};//int--能力值文字索引,double--能力值文字x坐标
Map<int,double> _yTextMap = {};//int--能力值文字索引,double--能力值文字y坐标
var _dividerPaint = Paint()..color = Colors.white..style = PaintingStyle.stroke..strokeWidth = 1.5..strokeCap = StrokeCap.round;
for(int i = 0; i < _colorList.length;i++){
Map<int,double> _xMap = {};//int--点索引,double--点x坐标
Map<int,double> _yMap = {};//int--点索引,double--点y坐标
for(int j = 0; j < _ab.length;j++){
double r = _r * (_colorList.length - 1 - i)/_colorList.length;
var _x = (r+30) * cos(j*_angle - pi /2);//加30是让最中间的圈大一点
var _y = (r+30) * sin(j*_angle - pi /2);//加30是让最中间的圈大一点
_xMap[j] = _x;
_yMap[j] = _y;
if(i == 0){
_xPointMap[j] = _ab[j]/100 * ((r+30)*cos(j*_angle - pi /2));//这边加30是为了和上面的半径保持一致
_yPointMap[j] = _ab[j]/100 * ((r+30)*sin(j*_angle - pi /2));//这边加30是为了和上面的半径保持一致
_xTextMap[j] = (r+60)*cos(j*_angle - pi /2);//字只需要延长半径即可
_yTextMap[j] = (r+50)*sin(j*_angle - pi /2);//字只需要延长半径即可
}
}
_xPointList.add(_xMap);
_yPointList.add(_yMap);
}
var _paint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true;
//画出渐变色背景板
for(int i = 0;i < _xPointList.length;i++){
canvas.save();
Map<int,double> xMap = _xPointList[i];
Map<int,double> yMap = _yPointList[i];
Path bg = Path();
bg.moveTo(xMap[0], yMap[0]);
for(int j = 1;j < _ab.length;j++){
bg.lineTo(xMap[j], yMap[j]);
}
canvas.drawPath(bg,_paint..color = _colorList[i]);
canvas.restore();
}
//画出白色分割线
for(int i = 0;i < _ab.length;i++){
canvas.drawLine(Offset(0, 0), Offset(_xPointList[0][i], _yPointList[0][i]), _dividerPaint);
}
//画出文字
var pc = ParagraphConstraints(width: 70);//根据文字数量微调
for(int i = 0;i < _ab.length;i++){
ParagraphBuilder pb = ParagraphBuilder(ParagraphStyle(
textAlign: TextAlign.center,
fontStyle: FontStyle.normal,
fontSize: 12
))
..pushStyle(ui.TextStyle(color: Color.fromARGB(255, 96, 63, 84)))
..addText('${_abName[i]}\n${_ab[i]}');
var paragraph = pb.build()..layout(pc);
canvas.drawParagraph(paragraph, Offset(_xTextMap[i]-35, _yTextMap[i]-15));//根据需求微调
}
Path point = Path();//能力值的线条
point.moveTo(_xPointMap[0], _yPointMap[0]);
for(int i = 1;i < _xPointMap.length;i++){
point.lineTo(_xPointMap[i], _yPointMap[i]);
}
point.close();
canvas.drawPath(point, _paint..color = Color.fromARGB(177, 96, 63, 84));
var _linePaint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..isAntiAlias = true;
canvas.drawPath(point, _linePaint..color = Color.fromARGB(255, 96, 63, 84));
canvas.save();
canvas.restore();
}
}