Flutter实现带线条相切圆UI:全平板与屏幕适配方案问询
Flutter 实现自适应相切圆带线条UI
实现思路
- 用
CustomPainter自定义绘制,精准控制圆与线条的几何关系 - 基于设备屏幕最短边动态计算圆的基准半径,保证在手机、平板等所有设备上都能完整适配
- 通过几何定位确保圆与圆、圆与线条的相切效果
完整代码实现
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '相切圆UI', theme: ThemeData(primarySwatch: Colors.blue), home: const Scaffold(body: Center(child: TangentCircleWidget())), ); } } class TangentCircleWidget extends StatelessWidget { const TangentCircleWidget({super.key}); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { // 以屏幕最短边的1/4作为基准半径,避免UI超出屏幕 final baseRadius = constraints.biggest.shortestSide / 4; return CustomPaint( size: constraints.biggest, painter: TangentCirclePainter(baseRadius: baseRadius), ); }, ); } } class TangentCirclePainter extends CustomPainter { final double baseRadius; TangentCirclePainter({required this.baseRadius}); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final paint = Paint() ..color = Colors.blue ..style = PaintingStyle.stroke ..strokeWidth = 2; // 绘制中心圆 canvas.drawCircle(center, baseRadius, paint); // 顶部相切圆及连接线 final topCenter = Offset(center.dx, center.dy - 2 * baseRadius); canvas.drawCircle(topCenter, baseRadius, paint); canvas.drawLine( Offset(center.dx, center.dy - baseRadius), Offset(topCenter.dx, topCenter.dy + baseRadius), paint, ); // 右侧相切圆及连接线 final rightCenter = Offset(center.dx + 2 * baseRadius, center.dy); canvas.drawCircle(rightCenter, baseRadius, paint); canvas.drawLine( Offset(center.dx + baseRadius, center.dy), Offset(rightCenter.dx - baseRadius, rightCenter.dy), paint, ); // 底部相切圆及连接线 final bottomCenter = Offset(center.dx, center.dy + 2 * baseRadius); canvas.drawCircle(bottomCenter, baseRadius, paint); canvas.drawLine( Offset(center.dx, center.dy + baseRadius), Offset(bottomCenter.dx, bottomCenter.dy - baseRadius), paint, ); // 左侧相切圆及连接线 final leftCenter = Offset(center.dx - 2 * baseRadius, center.dy); canvas.drawCircle(leftCenter, baseRadius, paint); canvas.drawLine( Offset(center.dx - baseRadius, center.dy), Offset(leftCenter.dx + baseRadius, leftCenter.dy), paint, ); } @override bool shouldRepaint(covariant TangentCirclePainter oldDelegate) { return oldDelegate.baseRadius != baseRadius; } }
适配说明
- 借助
LayoutBuilder获取父容器尺寸,动态计算圆的半径,适配不同屏幕大小 - 以屏幕最短边为基准计算半径,确保UI不会超出设备可视范围
- 所有元素的位置都基于中心坐标和基准半径推导,保证相切关系的准确性
内容的提问来源于stack exchange,提问作者Rajesh
相关产品推荐
相关产品推荐

