1. 程式人生 > 程式設計 >Flutter 通過Clipper實現各種自定義形狀的示例程式碼

Flutter 通過Clipper實現各種自定義形狀的示例程式碼

本文介紹了Flutter 通過Clipper實現各種自定義形狀的示例程式碼,分享給大家,具體如下:

ClipOval 圓形裁剪

ClipOval(
 child: SizedBox(
  width: 120.0,height: 120.0,child: Image.asset(
   Config.assets_avatar_1,),);

CircleAvatar 圓形頭像

CircleAvatar(
 radius: 60.0,backgroundImage: AssetImage(
  Config.assets_avatar_1,);

Container Decoration 裝飾形狀

通過BoxShape.circle實現圓形圖片

Container(
 width: 120.0,decoration: BoxDecoration(
  shape: BoxShape.circle,image: DecorationImage(
   image: AssetImage(
    Config.assets_avatar_1,)
);

通過BorderRadius實現圓形圖片

Container(
 width: 120.0,decoration: BoxDecoration(
  borderRadius: BorderRadius.all(Radius.circular(60.0)),image: DecorationImage(
    image: AssetImage(
     Config.assets_avatar_1,)

ClipPath 路徑剪裁

ClipPath(
 clipper: TriangleClipper(ClipperPosition.LeftTop),child: Container(
  width: 16.0,height: 16.0,decoration: BoxDecoration(
   color: Colors.blue,);

enum ClipperPosition {
 LeftTop,RightTop,}

class TriangleClipper extends CustomClipper<Path> {
 final ClipperPosition position;
 TriangleClipper(this.position);

 @override
 Path getClip(Size size) {
  final path = Path();
  path.lineTo(0.0,0.0);
  if (position == ClipperPosition.LeftTop) {
   path.lineTo(size.width,0.0);
   path.lineTo(size.width,size.height);
  } else if (position == ClipperPosition.RightTop) {
   path.lineTo(size.width,0.0);
   path.lineTo(0.0,size.height);
  }
  path.close();
  return path;
 }

 @override
 bool shouldReclip(CustomClipper oldClipper) {
  return false;
 }
}

ClipRect 矩形剪裁

Container(
 alignment: Alignment.topCenter,color: Colors.transparent,child: Container(
  color: Colors.green,child: ClipRect(
   clipper: _RectClipper(20.0),child: Image.asset(
    Config.assets_avatar_1,width: 160.0,height: 160.0,fit: BoxFit.fill,);

class _RectClipper extends CustomClipper<Rect> {
 /// Remove side of size
 final double removeSize;
 
 _RectClipper(this.removeSize);
 
 @override
 Rect getClip(Size size) {
  return new Rect.fromLTRB(
   removeSize,removeSize,size.width - removeSize,size.height - removeSize,);
 }
 
 @override
 bool shouldReclip(CustomClipper<Rect> oldClipper) {
  return false;
 }
}

ClipRRect 圓角矩形剪裁

ClipRRect(
 borderRadius: BorderRadius.all(Radius.circular(16.0)),child: Image.asset(
  Config.assets_avatar_1,width: 120.0,);

Star Rating(CustomPaint) 評分控制元件

評分控制元件 UI圖

實現方案

使用CustomPaint結合ClipPath畫出單個五角星;

  • 使用Stack渲染兩層畫面
  • 背景層,一排灰色五角星 前景層,一排亮色五角星,並使用ClipRect擷取一定Width

實現程式碼

class StarRatingDemo extends StatefulWidget {
 @override
 _StarRatingDemoState createState() => _StarRatingDemoState();
}

class _StarRatingDemoState extends State<StarRatingDemo> {
 /// ClipPath Star Rating
 _buildClipPathStarRating(double rate,int count) {
  return Container(
   padding: EdgeInsets.fromLTRB(24.0,16.0,24.0,0.0),child: StaticRatingBar(
    size: 50.0,rate: rate,count: count,);
 }
 
 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
    centerTitle: true,title: Text('Star Rating'),body: ListView(
    physics: BouncingScrollPhysics(),children: <Widget>[
     // _buildClipPathStarRating(1.0,1),_buildClipPathStarRating(0.5,5),_buildClipPathStarRating(2.0,_buildClipPathStarRating(3.0,_buildClipPathStarRating(4.0,_buildClipPathStarRating(5.0,_buildClipPathStarRating(5.5,6),SizedBox(height: 16.0),],);
 }
}

class StaticRatingBar extends StatelessWidget {
 /// Number of stars
 final int count;
 
 /// Init rate
 final double rate;
 
 /// Size of the starts
 final double size;
 
 final Color colorLight;
 
 final Color colorDark;
 
 StaticRatingBar({
  this.rate = 5,this.colorLight = const Color(0xFF1E88E5),this.colorDark = const Color(0xFFEEEEEE),this.count = 5,this.size = 60,});
 
 Widget buildDarkStar() {
  return SizedBox(
   width: size * count,height: size,child: CustomPaint(
    painter: _PainterStars(
     count: count,color: colorDark,strokeWidth: 0.0,size: this.size / 2,style: PaintingStyle.fill,);
 }
 
 Widget buildLightStar() {
  return ClipRect(
   clipper: _RatingBarClipper(rate * size),child: SizedBox(
    height: size,width: size * count,child: CustomPaint(
     painter: _PainterStars(
      count: count,color: colorLight,);
 }
 
 @override
 Widget build(BuildContext context) {
  return Stack(
   children: <Widget>[
    buildDarkStar(),buildLightStar(),);
 }
}

class _RatingBarClipper extends CustomClipper<Rect> {
 final double width;
 
 _RatingBarClipper(this.width);
 
 @override
 Rect getClip(Size size) {
  return Rect.fromLTRB(0.0,0.0,width,size.height);
 }
 
 @override
 bool shouldReclip(_RatingBarClipper oldClipper) {
  return false;
 }
}

class _PainterStars extends CustomPainter {
 final double size;
 final int count;
 final Color color;
 final PaintingStyle style;
 final double strokeWidth;
 
 _PainterStars({
  this.size,this.count,this.color,this.strokeWidth,this.style,});

 double degree2Radian(int degree) {
  return (pi * degree / 180);
 }

 Path createStarPath(double radius,Path path) {
  double radian = degree2Radian(36);
  double radiusIn = (radius * sin(radian / 2) / cos(radian)) * 1.1;
  path.moveTo((radius * cos(radian / 2)),0.0);
  path.lineTo(
   (radius * cos(radian / 2) + radiusIn * sin(radian)),(radius - radius * sin(radian / 2)),);
  path.lineTo(
   (radius * cos(radian / 2) * 2),);
  path.lineTo(
   (radius * cos(radian / 2) + radiusIn * cos(radian / 2)),(radius + radiusIn * sin(radian / 2)),);
  path.lineTo(
   (radius * cos(radian / 2) + radius * sin(radian)),(radius + radius * cos(radian)),);
  path.lineTo((radius * cos(radian / 2)),(radius + radiusIn));
  path.lineTo(
   (radius * cos(radian / 2) - radius * sin(radian)),);
  path.lineTo(
   (radius * cos(radian / 2) - radiusIn * cos(radian / 2)),);
  path.lineTo(0.0,(radius - radius * sin(radian / 2)));
  path.lineTo(
   (radius * cos(radian / 2) - radiusIn * sin(radian)),0.0);
  return path;
 }

 @override
 void paint(Canvas canvas,Size size) {
  Paint paint = Paint();
  paint.strokeWidth = strokeWidth;
  paint.color = color;
  paint.style = style;
  Path path = Path();
  double offset = strokeWidth > 0 ? strokeWidth + 2 : 0.0;
  
  path = createStarPath(this.size - offset,path);
  for (int i = 0; i < count - 1; i++) {
   path = path.shift(Offset(this.size * 2,0.0));
   path = createStarPath(this.size - offset,path);
  }
 
  if (offset > 0) {
   path = path.shift(Offset(offset,offset));
  }
  path.close();
  canvas.drawPath(path,paint);
 }
 
 @override
 bool shouldRepaint(_PainterStars oldDelegate) {
  return oldDelegate.size != this.size;
 }
}

程式碼地址

https://github.com/smiling1990/FlutterClipper

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。