1 Icon
Icon是图标控件,Icon不具有交互属性。
2024年08月03日
在Flutter默认创建的项目中可以使用系统Material图标,在pubspec.yaml文件中使用图标设置如下:
flutter:
uses-material-design: true
2024年04月26日
完美的插件,通常能够大幅度提高开发者的效率。VSCODE 插件安装在左侧菜单栏标红出
下面开始我们的插件推荐
快捷调试,实时同步异常方便
2024年04月26日
实现UI和交互是大前端开发者的必备技能,也是掌握Flutter开发的重点;在下学习Flutter之际,实现了几种客户端上常见的酷炫UI特效,虽说是用Flutter造原生的轮子,但Flutter跨平台的特性是原生不能比拟的,更何况还有不弱的性能表现。本文主要是介绍Flutter特效库flutter_effects的基本情况和使用;
2024年04月26日
最近一段时间,阿里巴巴旗下闲鱼客户端团队完成了基于Flutter混合架构的闲鱼客户端的整体架构设计,在工程体系上完善了针对Flutter的持续集成以及高可用体系的支撑,同时推进了闲鱼主链路业务的Flutter化,未来也将持续推进该终端技术的产品演变。
2024年04月26日
新版本包括增强 iOS 端性能的 Metal 支持、新的 Material 组件和新的 Network 跟踪工具等! 结尾有干货。
今天我们很高兴为大家带来了 Flutter 1.17,也是我们 2020 年的第一个稳定版本。
对所有人来说今年都是充满挑战的一年。我们的目标是大约每个季度发布一个稳定版本,但这次的版本花费的时间要长一些,因为我们一直在针对新的发布流程调整我们的基础架构:
2024年04月26日
功能不完善,只是单纯的实现功能,作为记录,仅供参考:
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lifeline/utils/hex_color_utils.dart';
class RingComponent extends StatelessWidget {
final double radius;
final Function onTap;
RingComponent({ required this.radius, required this.onTap });
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: radius * 2,
height: radius * 2,
child: CustomPaint(
painter: RingPainter(width: radius*0.6, radius: radius),
),
),
SizedBox(
width: radius * 0.9,
height: radius * 0.9,
child: FloatingActionButton(
onPressed: () {onTap();},
mini: false,
materialTapTargetSize: MaterialTapTargetSize.padded,
child: const Icon(
Icons.sticky_note_2,
color: Colors.white,
),
),
),
],
);
}
}
class RingPainter extends CustomPainter {
final double width;
final double radius;
RingPainter({required this.width, required this.radius});
@override
void paint(Canvas canvas, Size size) {
final rect = Rect.fromCircle(
center: size.center(Offset.zero), radius: size.width / 2);
canvas.translate(20.w, -15.w);
canvas.save();
canvas.rotate(math.pi / 9);
const startAngle = -math.pi / 2;
const sweepAngle = math.pi * 2 / 3;
final innerRadius = size.width / 2 - width / 2;
final outerRadius = size.width / 2 + width / 2;
final innerPoint1 =
calculatePointOnRing(size, startAngle + sweepAngle, innerRadius);
final innerPoint2 =
calculatePointOnRing(size, startAngle + 2 * sweepAngle, innerRadius);
final innerPoint3 =
calculatePointOnRing(size, startAngle + 3 * sweepAngle, innerRadius);
final outerPoint1 =
calculatePointOnRing(size, startAngle + sweepAngle, outerRadius);
final outerPoint2 =
calculatePointOnRing(size, startAngle + 2 * sweepAngle, outerRadius);
final outerPoint3 =
calculatePointOnRing(size, startAngle + 3 * sweepAngle, outerRadius);
final colors = [HexColor("516fd5"), HexColor("f8df2d"), HexColor("f2eeeb")];
final texts = ['Intervention', 'Plan', 'Reflection'];
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = width;
for (int i = 0; i < colors.length; i++) {
paint.color = colors[i];
final start = startAngle + i * sweepAngle;
const sweep = sweepAngle;
canvas.drawArc(rect, start, sweep, false, paint);
}
final arrowBluePaint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true
..color = HexColor("516fd5");
final arrowBluePath = Path();
arrowBluePath.moveTo(innerPoint1.dx + 0.6, innerPoint1.dy);
arrowBluePath.lineTo(outerPoint1.dx, outerPoint1.dy - 0.4);
arrowBluePath.lineTo(
innerPoint1.dx, innerPoint1.dy + math.sqrt(1 / 2) * width + 5);
arrowBluePath.close();
canvas.drawPath(arrowBluePath, arrowBluePaint);
final arrowYellowPaint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true
..color = HexColor("f8df2d");
final arrowYellowPath = Path();
arrowYellowPath.moveTo(innerPoint2.dx + 0.2, innerPoint2.dy);
arrowYellowPath.lineTo(outerPoint2.dx, outerPoint2.dy + 0.4);
arrowYellowPath.lineTo(
outerPoint2.dx, outerPoint2.dy - math.sqrt(1 / 2) * width - 5);
arrowYellowPath.close();
canvas.drawPath(arrowYellowPath, arrowYellowPaint);
final arrowGrayPaint = Paint()
..style = PaintingStyle.fill
..isAntiAlias = true
..color = HexColor("f2eeeb");
final arrowGrayPath = Path();
arrowGrayPath.moveTo(innerPoint3.dx, innerPoint3.dy);
arrowGrayPath.lineTo(outerPoint3.dx, outerPoint3.dy);
arrowGrayPath.lineTo(
0.6 * width + outerPoint3.dx, outerPoint3.dy + 1 / 2 * width + 5);
arrowGrayPath.close();
canvas.drawPath(arrowGrayPath, arrowGrayPaint);
// draw text
canvas.restore();
final textPainter = TextPainter(
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
for (int i = 0; i < texts.length; i++) {
final textSpan = TextSpan(
text: texts[i],
style: TextStyle(fontSize: 10.sp, color: Colors.grey),
);
textPainter.text = textSpan;
textPainter.layout();
double x;
double y;
if (i == 2) {
//reflection
x = (outerPoint1.dx + outerPoint2.dx) / 2 -
textPainter.width / 2 -
radius * 0.8;
y = (outerPoint1.dy + outerPoint2.dy) / 2 +
radius * 0.5 -
textPainter.height / 2;
} else if (i == 0) {
//intervention
x = (outerPoint2.dx + outerPoint3.dx) / 2 -
textPainter.width / 2 +
radius * 0.1;
y = (outerPoint2.dy + outerPoint3.dy) / 2 +
radius * 0.5 -
textPainter.height / 2 -
radius * 0.8;
} else {
//plan
x = (outerPoint3.dx + outerPoint1.dx) / 2 - textPainter.width / 2;
y = (outerPoint3.dy + outerPoint1.dy) / 2 +
radius * 0.7 -
textPainter.height / 2;
}
final textOffset = Offset(x, y);
textPainter.paint(canvas, textOffset);
}
}
Offset calculatePointOnRing(Size size, double angle, double radius) {
final centerX = size.width / 2;
final centerY = size.height / 2;
final x = centerX + math.cos(angle) * radius;
final y = centerY + math.sin(angle) * radius;
return Offset(x, y);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
2024年04月26日
我写了一本 《Flutter实战》 推荐给大家。 在线阅读地址:https://book.flutterchina.club
2024年04月26日
本文为Flutter应用开发的第一篇文章,我们将通过几个Flutter实例来演示下Flutter平台下界面开发的一个重要概念:一切皆为组件。本文将在Windows 11操作系统下使用Android Studio进行Flutter应用的开发,我们首先通过菜单File|New Flutter Project...
2024年04月26日
Flutter应用程序可以包含代码和 assets(有时称为资源)。assets是会打包到程序安装包中的,可在运行时访问。常见类型的assets包括静态数据(例如JSON文件)、配置文件、图标和图片(JPEG,WebP,GIF,动画WebP / GIF,PNG,BMP和WBMP)等。
指定 assets