1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flutterでカスタムマーカーを作った

Posted at

作れるものイメージ

スクリーンショット 2024-11-08 215203.png

作り方

PictureRecorderとCanvasを使います

今回はmarkerに数字を与えたく、引数にindexを与えられるような実装にしてみました

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

class CustomMarkerIcon {
  static Future<BitmapDescriptor> createMarkerIcon(int index) async {
    // マーカーのサイズを定義
    const int markerWidth = 50; // 幅
    const double circleRadius = 15; // 円の半径
    const double triangleHeight = 30; // 三角形の高さ
    const double triangleBaseWidth = circleRadius * 2; // 三角形の底辺の幅(円の直径に合わせる)
    const double overlapOffset = circleRadius / 2; // 円と三角形の重なりを調整するオフセット

    // 描画を開始
    final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
    final Canvas canvas = Canvas(pictureRecorder);

    // 円を描画(やや下に配置して三角形と重ねる)
    final Paint paint = Paint()..color = Colors.blue;
    const Offset circleCenter =
        Offset(markerWidth / 2, circleRadius + overlapOffset);
    canvas.drawCircle(circleCenter, circleRadius, paint);

    // 逆三角形を描画(やや上に配置して円と重ねる)
    final Path trianglePath = Path()
      ..moveTo((markerWidth - triangleBaseWidth) / 2,
          circleRadius * 2 - overlapOffset) // 左上
      ..lineTo((markerWidth + triangleBaseWidth) / 2,
          circleRadius * 2 - overlapOffset) // 右上
      ..lineTo(markerWidth / 2,
          circleRadius * 2 + triangleHeight - overlapOffset) // 頂点
      ..close();
    canvas.drawPath(trianglePath, paint);

    // 円の中央にテキスト(index)を描画
    final TextPainter textPainter = TextPainter(
      text: TextSpan(
        text: "$index",
        style: const TextStyle(
          fontSize: 12.0, 
          color: Colors.white,
          fontWeight: FontWeight.bold,
        ),
      ),
      textDirection: TextDirection.ltr,// お作法的に必要
    );
    textPainter.layout();
    final Offset textOffset = Offset(
      (markerWidth - textPainter.width) / 2,
      circleCenter.dy - textPainter.height / 2,
    );
    textPainter.paint(canvas, textOffset);

    // Canvasを画像に変換
    final ui.Image markerImage = await pictureRecorder.endRecording().toImage(
          markerWidth,
          (circleRadius * 2 + triangleHeight - overlapOffset).toInt(),
        );
    final ByteData? byteData =
        await markerImage.toByteData(format: ui.ImageByteFormat.png);

    if (byteData == null) return BitmapDescriptor.defaultMarker;

    // ByteDataからBitmapDescriptorを作成
    return BitmapDescriptor.bytes(byteData.buffer.asUint8List());
  }
}

使い方

import 'package:google_maps_flutter/google_maps_flutter.dart';

final markers = <Marker>{};
markers.add(
    Marker(
        position: const LatLng(35.6811673, 139.7670516),
        markerId: MarkerId("$markerId"),
        icon: await CustomMarkerIcon.createMarkerIcon(markerId)
    )
);

// GoogleMapウィジェットのmarkersフィールドにセットして使用
GoogleMap(
    markers: markers
)

ちょっと解説

Canvasを使って、図形を重ねているだけです。
かなり計算が多く、どんな形でも行けるわけではありませんが適宜変更すればそれっぽいものが作れるのではないでしょうか?

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?