You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:15:31