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

Flutter中创建随机位置、不同半径的响应式圆形技术求助

实现响应式随机位置与半径的圆形布局

核心思路

用LayoutBuilder获取当前可用空间尺寸,结合Random生成每个圆的位置、半径和颜色,通过两种方式绘制(简单的Stack布局或高性能的CustomPainter),确保布局在屏幕尺寸变化时自动适配。

步骤1:定义圆的数据模型

先创建一个类存储每个圆的关键参数:

class CircleData {
  final double x;
  final double y;
  final double radius;
  final Color color;

  CircleData({required this.x, required this.y, required this.radius, required this.color});
}

步骤2:生成随机圆数据

编写方法生成符合响应式要求的随机圆,同时避免圆超出边界或重叠(可选):

import 'dart:math';

List<CircleData> generateRandomCircles(int count, double maxWidth, double maxHeight) {
  final random = Random();
  final circles = <CircleData>[];
  for (int i = 0; i < count; i++) {
    CircleData? newCircle;
    // 最多尝试10次生成不重叠的圆,防止无限循环
    for (int j = 0; j < 10; j++) {
      // 限制半径范围:最小10,最大为可用最短边的1/8
      final radius = 10 + random.nextDouble() * (min(maxWidth, maxHeight) / 8 - 10);
      // 计算位置,确保圆不会完全超出容器边界
      final x = radius + random.nextDouble() * (maxWidth - 2 * radius);
      final y = radius + random.nextDouble() * (maxHeight - 2 * radius);
      // 生成带透明度的随机颜色
      final color = Color.fromRGBO(
        random.nextInt(256),
        random.nextInt(256),
        random.nextInt(256),
        0.7 + random.nextDouble() * 0.3,
      );
      final candidate = CircleData(x: x, y: y, radius: radius, color: color);
      
      // 检测是否与已有圆重叠(可选,不需要可删除这段)
      bool overlaps = false;
      for (final circle in circles) {
        final distance = sqrt(pow(candidate.x - circle.x, 2) + pow(candidate.y - circle.y, 2));
        if (distance < candidate.radius + circle.radius) {
          overlaps = true;
          break;
        }
      }
      if (!overlaps) {
        newCircle = candidate;
        break;
      }
    }
    if (newCircle != null) circles.add(newCircle);
  }
  return circles;
}

步骤3:实现响应式布局

提供两种实现方式,按需选择:

方式一:Stack + Positioned + Container(简单直观,适合少量圆)

class ResponsiveRandomCircles extends StatelessWidget {
  final int circleCount;

  const ResponsiveRandomCircles({super.key, this.circleCount = 10});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final circles = generateRandomCircles(circleCount, constraints.maxWidth, constraints.maxHeight);
        return Stack(
          children: circles.map((circle) {
            return Positioned(
              left: circle.x - circle.radius,
              top: circle.y - circle.radius,
              child: Container(
                width: circle.radius * 2,
                height: circle.radius * 2,
                decoration: BoxDecoration(
                  color: circle.color,
                  shape: BoxShape.circle,
                ),
              ),
            );
          }).toList(),
        );
      },
    );
  }
}

方式二:CustomPainter(性能更优,适合大量圆)

先定义绘制器:

class CirclePainter extends CustomPainter {
  final List<CircleData> circles;

  CirclePainter(this.circles);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..style = PaintingStyle.fill;
    for (final circle in circles) {
      paint.color = circle.color;
      canvas.drawCircle(Offset(circle.x, circle.y), circle.radius, paint);
    }
  }

  @override
  bool shouldRepaint(covariant CirclePainter oldDelegate) {
    return oldDelegate.circles != circles;
  }
}

再构建响应式组件:

class ResponsiveRandomCircles extends StatelessWidget {
  final int circleCount;

  const ResponsiveRandomCircles({super.key, this.circleCount = 10});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final circles = generateRandomCircles(circleCount, constraints.maxWidth, constraints.maxHeight);
        return CustomPaint(
          painter: CirclePainter(circles),
          size: Size(constraints.maxWidth, constraints.maxHeight),
        );
      },
    );
  }
}

使用方式

直接在页面中引用组件即可:

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: ResponsiveRandomCircles(circleCount: 15),
  );
}

关键说明

  • 响应式适配:LayoutBuilder会监听父容器尺寸变化,重新生成圆的参数,确保在不同屏幕或窗口大小下都能正确显示。
  • 参数调整:可以修改generateRandomCircles中的半径范围、颜色透明度、碰撞检测逻辑,匹配你的预期设计效果。
  • 性能优化:如果需要绘制大量圆形(比如50+),优先选择CustomPainter方式,减少Widget树节点数量。

内容的提问来源于stack exchange,提问作者Ayesha Iftikhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 23:47:33