我想在我的 Flutter 應用上顯示類似 Instagram 的故事,并希望通過使用用戶頭像周圍的邊框來顯示用戶上傳的故事數量。
假設用戶上傳了 3 個故事,我將在頭像影像周圍顯示 3 條圓形邊框線,由相同數量的空格分隔,如果用戶上傳 80 個故事,我將顯示 80 條由相同數量空格分隔的微小圓形邊框線。
我為此嘗試使用
知道如何使用CustomPainter()插件或插件來實作這一點嗎?
uj5u.com熱心網友回復:
感謝您發布所有嘗試,因為它讓我直接跳到 CustomPath() 嘗試
(可能)(未經過良好測驗)有效的方法是
完整代碼及詳細解釋:
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(),
),
);
}
uj5u.com熱心網友回復:
點擊查看圖片:


我們應該確定兩件事
- 顏色寬度
- 分隔寬度\
顏色寬度可以通過以下功能測量
double colorWidth(double radius, int statusCount, double separation)
{
return ((2 * pi * radius) - (statusCount * separation)) / statusCount;
}
2 * PI * 半徑 >> 圓周長
SO >> 周長減去所需的總分離像素,然后結果除以總狀態計數。
現在我們平等地擁有每個狀態的寬度,以適應圓形邊框
測量分離像素寬度
取決于狀態編號作為 WhatsApp 更加增強
double separation(int statusCount) {
if (statusCount <= 20)
return 3.0;
else if (statusCount <= 30)
return 1.8;
else if (statusCount <= 60)
return 1.0;
else
return 0.3;
}
現在我們將dotted_border包添加到我們的專案中并匯入它
https://pub.dev/packages/dotted_border
import 'package:dotted_border/dotted_border.dart';
假設我們上面有一些宣告,它們是:
//each digit express a status number
List status = [1, 2, 5, 4, 9, 13, 15, 20, 30, 40, 80];
//circle radius
double radius = 27.0;
破折號:
我們有兩種狀態一種狀態或多種狀態(多種狀態)
dashPattern: status[index] == 1
? [
//one status
(2 * pi * (radius 2)), // take all border
0, //zere separators
]
: [
//multiple status
colorWidth(radius 2, status[index],
separation(status[index])),
separation(status[index]),
],
完整代碼:
import 'dart:math';
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'STATUS',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
List status = [1, 2, 5, 4, 9, 13, 15, 20, 30, 40, 80];
double radius = 27.0;
double colorWidth(double radius, int statusCount, double separation) {
return ((2 * pi * radius) - (statusCount * separation)) / statusCount;
}
double separation(int statusCount) {
if (statusCount <= 20)
return 3.0;
else if (statusCount <= 30)
return 1.8;
else if (statusCount <= 60)
return 1.0;
else
return 0.3;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView.separated(
itemCount: status.length,
separatorBuilder: (context, index) => Divider(
color: Colors.black,
height: 15,
),
itemBuilder: ((context, index) => Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child:
/// Creating a circle with a dotted border.
DottedBorder(
color: Colors.teal.shade300,
borderType: BorderType.Circle,
radius: Radius.circular(radius),
dashPattern: status[index] == 1
? [
//one status
(2 * pi * (radius 2)),
0,
]
: [
//multiple status
colorWidth(radius 2, status[index],
separation(status[index])),
separation(status[index]),
],
strokeWidth: 3,
child: CircleAvatar(
radius: radius,
backgroundColor: Colors.transparent,
child: CircleAvatar(
radius: radius - 2,
),
),
),
),
SizedBox(
width: 10,
),
Text(
'${status[index]}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
)),
),
),
);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/467710.html
上一篇:如何限制UI中顯示的描述?
下一篇:JToggle按鈕背景顏色更改
