如何在颤振中围绕圆形头像创建虚线边框

2023-12-30

我想在我的 Flutter 应用程序上显示类似 Instagram 的故事,并希望通过使用用户头像周围的边框来显示用户上传的故事数量。

假设用户上传了 3 个故事,我将在头像图像周围显示 3 条圆形边框线,以相等数量的空格分隔;如果用户上传 80 个故事,我将显示 80 条微小的圆形边框线,以相等数量的空格分隔。

我尝试使用插件pub.dev https://pub.dev为此,就像

  • 虚线边框 2.0.0+2 https://pub.dev/packages/dotted_border
  • 点线1.0.1 https://pub.dev/packages/fdottedline

仅举几个例子,但我似乎无法准确计算空格和破折号来满足上述要求。

下面是一个例子:

FDottedLine(
  color: Colors.black,
  strokeWidth: 2.0,
  dottedLength: 30,
  space: 4,
  corner: FDottedLineCorner.all(100.0),
  child: Padding(
    padding: const EdgeInsets.all(3.0),
    child: SizedBox.square(
      dimension: 0.055.h,
      child: ClipRRect(
        borderRadius: BorderRadius.circular(100),
        child: ImageBox.network(
          photo: user.photo.getOrEmpty,
          elevation: 2,
          replacement: Image.asset(AppAssets.defaultUserImage(user.gender.getOrNull)),
          borderRadius: BorderRadius.circular(100),
        ),
      ),
    ),
  ),
),

无论我如何调整dottedLength & space参数,我无法获得相同数量的空格或破折号。

我也尝试过使用Path(), CustomPainter()但我对如何使用它知之甚少。

知道如何使用任一方法实现此目的CustomPainter()或者插件?


感谢您发布所有尝试,因为它让我跳到CustomPaint直接尝试

(可能)有效(但未经良好测试)的方法是drawArc https://api.flutter.dev/flutter/dart-ui/Canvas/drawArc.html

逻辑很简单,根据故事的数量绘制一条弧线,并在留出一些空间后开始下一条弧线

下面的代码循环绘制每个故事弧的故事数,并在将一些值(故事之间的空间)添加到下一个弧位置(在圆上)的开始之后开始下一个故事弧(如果故事数> 1) )。

    for(int i =0;i<numberOfStories;i++){
        canvas.drawArc(
            rect,
            inRads(startOfArcInDegree),
            inRads(arcLength),
            false,
            Paint()
             ..color = i==0||i==1?Colors.grey:Colors.teal
             ..strokeWidth =14.0
             ..style = PaintingStyle.stroke

  );
     startOfArcInDegree += arcLength + spaceLength;
}

完整代码及详细解释:

import 'dart:math';
import 'package:flutter/material.dart';

class DottedBorder extends CustomPainter {
  //number of stories
  final int numberOfStories;
  //length of the space arc (empty one)
  final int spaceLength;
  //start of the arc painting in degree(0-360)
  double startOfArcInDegree = 0;

  DottedBorder({required this.numberOfStories, this.spaceLength = 10});

  //drawArc deals with rads, easier for me to use degrees
  //so this takes a degree and change it to rad
  double inRads(double degree){
    return (degree * pi)/180;
  }

  @override
  bool shouldRepaint(DottedBorder oldDelegate) {
    return true;
  }

  @override
  void paint(Canvas canvas, Size size) {

    //circle angle is 360, remove all space arcs between the main story arc (the number of spaces(stories) times the  space length
    //then subtract the number from 360 to get ALL arcs length
    //then divide the ALL arcs length by number of Arc (number of stories) to get the exact length of one arc
    double arcLength = (360 - (numberOfStories * spaceLength))/numberOfStories;


    //be careful here when arc is a negative number
    //that happens when the number of spaces is more than 360
    //feel free to use what logic you want to take care of that
    //note that numberOfStories should be limited too here
    if(arcLength<=0){
      arcLength = 360/spaceLength -1;
    }


    Rect rect = Rect.fromLTWH(0, 0, size.width, size.height);

    //looping for number of stories to draw every story arc
    for(int i =0;i<numberOfStories;i++){
      //printing the arc
      canvas.drawArc(
          rect,
          inRads(startOfArcInDegree),
          //be careful here is:  "double sweepAngle", not "end"
          inRads(arcLength),
          false,
          Paint()
          //here you can compare your SEEN story index with the arc index to make it grey
            ..color = i==0||i==1?Colors.grey:Colors.teal
            ..strokeWidth =14.0
            ..style = PaintingStyle.stroke

      );

      //the logic of spaces between the arcs is to start the next arc after jumping the length of space
      startOfArcInDegree += arcLength + spaceLength;
    }    
  }
}



class DottedBorderExample extends StatelessWidget {
  const DottedBorderExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Arcs etc')),
      body:Center(
          child: Stack(
            alignment: Alignment.center,
            children: [
              SizedBox(
                width: 300,height: 300,

                child: CustomPaint(
                                    painter:  DottedBorder(numberOfStories: 13,spaceLength:4 ),
              ),),
              Container(child:const Center(child: Text("Some Image",style: TextStyle(fontSize: 18,color: Colors.black),)),width: 270,height: 270,decoration: const BoxDecoration(color: Colors.purple,shape: BoxShape.circle),)
            ],
          ),
       ),
    );
  }
}

void main() {
  runApp(
    const MaterialApp(
      home: DottedBorderExample(),
    ),
  );
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在颤振中围绕圆形头像创建虚线边框 的相关文章

随机推荐