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

Flutter Map中如何用图片填充多边形?

实现国旗填充国界多边形的Flutter方案

要实现国旗图片填充国界多边形的效果,核心是通过CustomPaint结合ImageShader来实现,以下是具体步骤和代码示例:

1. 准备核心资源

  • 国界坐标数据:获取目标国家的GeoJSON格式边界数据,提取其中的多边形坐标集合,再将经纬度坐标转换为Flutter画布的像素坐标(需根据你的地图布局逻辑做映射,比如缩放、平移适配)。
  • 国旗图片:准备对应国家的国旗图片,放在项目assets目录下并在pubspec.yaml中配置资源路径。

2. 自定义绘制逻辑

通过CustomPainter创建自定义绘制器,用国旗图片生成Shader,再填充国界路径:

加载国旗图片

先封装一个加载图片的工具方法,将asset图片转为Flutter的Image对象:

import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/services.dart';

Future<ui.Image> loadFlagImage(String assetPath) async {
  final ByteData data = await rootBundle.load(assetPath);
  final Uint8List bytes = data.buffer.asUint8List();
  return await ui.decodeImageFromList(bytes);
}

实现自定义Painter

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

class FlagFillPainter extends CustomPainter {
  final ui.Image flagImage;
  final List<Offset> countryPathPoints;

  FlagFillPainter({
    required this.flagImage,
    required this.countryPathPoints,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // 构建国界闭合路径
    final Path countryPath = Path();
    if (countryPathPoints.isNotEmpty) {
      countryPath.moveTo(countryPathPoints[0].dx, countryPathPoints[0].dy);
      for (int i = 1; i < countryPathPoints.length; i++) {
        countryPath.lineTo(countryPathPoints[i].dx, countryPathPoints[i].dy);
      }
      countryPath.close();
    }

    // 创建图片着色器,可调整TileMode控制图片超出路径时的显示方式
    final Shader flagShader = ui.ImageShader(
      flagImage,
      TileMode.clamp, // 超出部分拉伸边缘像素
      TileMode.clamp,
      Matrix4.identity().storage, // 可通过矩阵调整图片缩放、平移
    );

    // 配置画笔,使用着色器填充路径
    final Paint fillPaint = Paint()..shader = flagShader;
    // 可选:绘制国界边框
    final Paint borderPaint = Paint()
      ..color = Colors.black
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.5;

    canvas.drawPath(countryPath, fillPaint);
    canvas.drawPath(countryPath, borderPaint);
  }

  @override
  bool shouldRepaint(covariant FlagFillPainter oldDelegate) {
    return flagImage != oldDelegate.flagImage ||
        countryPathPoints != oldDelegate.countryPathPoints;
  }
}

3. 在页面中使用

通过FutureBuilder处理图片加载状态,再渲染CustomPaint:

class FlagMapPage extends StatefulWidget {
  const FlagMapPage({super.key});

  @override
  State<FlagMapPage> createState() => _FlagMapPageState();
}

class _FlagMapPageState extends State<FlagMapPage> {
  late Future<ui.Image> _flagImage;
  // 示例:替换为实际转换后的国界像素坐标集合
  final List<Offset> _countryPoints = [
    Offset(150, 100),
    Offset(350, 100),
    Offset(350, 300),
    Offset(150, 300),
  ];

  @override
  void initState() {
    super.initState();
    // 加载assets中的国旗图片
    _flagImage = loadFlagImage('assets/flags/china_flag.png');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('国旗填充国界')),
      body: Center(
        child: FutureBuilder<ui.Image>(
          future: _flagImage,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return CustomPaint(
                size: const Size(500, 400),
                painter: FlagFillPainter(
                  flagImage: snapshot.data!,
                  countryPathPoints: _countryPoints,
                ),
              );
            } else if (snapshot.hasError) {
              return const Text('国旗加载失败');
            }
            return const CircularProgressIndicator();
          },
        ),
      ),
    );
  }
}

关键注意事项

  • 坐标转换:GeoJSON的经纬度需要根据你的地图视图(比如缩放级别、中心点)转换成画布像素坐标,可通过线性映射公式或第三方地图库的坐标转换API实现。
  • 性能优化:复杂国界的GeoJSON坐标点数量极多,建议先简化坐标点(比如使用抽稀算法),避免绘制卡顿;如果是多国家场景,可考虑缓存绘制结果。
  • 图片适配:若国旗比例与多边形比例不匹配,可修改ImageShader的矩阵参数(比如Matrix4.scale)来调整图片缩放,让填充效果更自然。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 12:04:55