Flutter自定义组件(绘制五角星组件)

2022-05-10  本文已影响0人  android不是安卓

何用canvas绘制我们任何想要任意图案的组件,这篇文章用自定义一个五角星组件来说明。

CsutomPaint

自定义组件,建议用官方的CustomPaint来实现,先新建一个pantagram的类

class Pentagram extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.black;
    final rect = Offset.zero & size;
    canvas.drawRect(rect, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

它是继承CustomPainter这个类,有两个方法,shouldRepaint先写死返回false,paint方法就是真实绘制的地方,这里先绘制一个黑色的矩形
然后在页面引用这个类

return Scaffold(              
  appBar: AppBar(             
    title: Text('Demo Page'), 
  ),                           
  body: Center(               
    child: CustomPaint(       
      painter: Pentagram(),   
    ),                         
  ),                           
);    

运行后,发现页面是空白的,查看了下它的源码,发现是size的问题

const CustomPaint({            
  Key? key,                    
  this.painter,                
  this.foregroundPainter,      
  this.size = Size.zero, //尺寸默认是0       

size默认的尺寸是0,重新设置size后,显示正常了(个人觉得,默认的size用size.infinite更合理,充满父布局)


使用自定义组件,绘制出了一块黑色的矩形了

绘制path

由于五角星属于特殊的图案,需要手动设置path,为了验证path的可行性,先绘制一个菱形来做验证

void paint(Canvas canvas, Size size) {       
  //把画笔设置成stroke模式                           
  final paint = Paint()                      
    ..color = Colors.black                   
    ..style = PaintingStyle.stroke           
    ..strokeWidth = 2;                       
  var rect = Offset.zero & size;             
  var center = rect.center;                  
  // 连接好菱形的四个顶点                              
  final path = Path();                       
  path.moveTo(center.dx, 0);                 
  path.lineTo(rect.right, center.dy);        
  path.lineTo(center.dx, rect.bottom);       
  path.lineTo(0, center.dy);                 
  path.close(); //最后用close的方式把path封闭起来       
  // 调用canvas绘制path                          
  canvas.drawPath(path, paint);              
}             

先把画笔设置成stroke模式,然后path连接好菱形的四个顶点,最后直接绘制即可,效果如下:

菱形绘制好了,说明path的方案可行

绘制五角星

既然path方案可行,接来下就是确定五角星的五个顶点,用path连接起来,代码如下:

Path getPentagramPath(double radius) {                         
  var initDegreen = 180;                                       
  // 连接五角星的五个顶点                                                
  final path = Path();                                         
  var posOne = getOffsetPosition(initDegreen, radius);         
  path.moveTo(posOne.dx, posOne.dy);                           
  // 360/5,每个是72度                                              
  var posTwo = getOffsetPosition(72 + initDegreen, radius);    
  path.lineTo(posTwo.dx, posTwo.dy);                           
  var posThree = getOffsetPosition(144 + initDegreen, radius); 
  path.lineTo(posThree.dx, posThree.dy);                       
  var posfour = getOffsetPosition(216 + initDegreen, radius);  
  path.lineTo(posfour.dx, posfour.dy);                         
  var posFive = getOffsetPosition(288 + initDegreen, radius);  
  path.lineTo(posFive.dx, posFive.dy);                         
  //最后用close的方式把path封闭起来                                       
  path.close();                                                
  return path;                                                 
}                                                              
                                                               
Offset getOffsetPosition(int degreen, double radius) {         
  //角度转成弧度                                                     
  var radian = degreen * pi / 180;                             
  var dx = sin(radian) * radius;                               
  var dy = cos(radian) * radius;                               
  return Offset(dx + radius, dy + radius);                     
}                 
看下效果图:

结果变成五边形了,不是我们要的五角星,需要把path的线条连接方式修改下:

var initDegreen = 180;                                      
// 连接五角星的五个顶点,360/5,每个是72度                                  
final path = Path();                                        
var posOne = getOffsetPosition(initDegreen, radius);        
var posTwo = getOffsetPosition(72 + initDegreen, radius);   
var posThree = getOffsetPosition(144 + initDegreen, radius);
var posfour = getOffsetPosition(216 + initDegreen, radius); 
var posFive = getOffsetPosition(288 + initDegreen, radius); 
path.moveTo(posOne.dx, posOne.dy);                          
path.lineTo(posfour.dx, posfour.dy);                        
path.lineTo(posTwo.dx, posTwo.dy);                          
path.lineTo(posFive.dx, posFive.dy);                        
path.lineTo(posThree.dx, posThree.dy);                      
//最后用close的方式把path封闭起来                                      
path.close();              

这次终于看到我们需要的效果:

这个五角星,如果要用填充的方式展示,只需要把画笔style设置成fill即可.

final paint = Paint()            
  ..color = Colors.black         
  ..style = PaintingStyle.fill;  

效果如下:

传参

对于自定义组件,想要一些参数,是可以外部控制的,比如五角星的颜色,可以用外部传进来。

class Pentagram extends CustomPainter {
  Pentagram(this.color);
  //画笔的颜色
  final Color color;

先定义好需要外部设置的参数,外部在使用的地方,把颜色设置进来

child: CustomPaint(                  
  size: Size(150, 150),          
  painter: Pentagram(Colors.black),  
),             

包括动态调整颜色和其他熟悉,也都可以实现了。

转载自作者:韦东锏
https://mp.weixin.qq.com/s/XV_FdANJWQijuzKKpJffkw

上一篇下一篇

猜你喜欢

热点阅读