Как изменить размер значка маркера Google Map во флаттере? - PullRequest
0 голосов
/ 05 декабря 2018

Я использую google_maps_flutter в своем приложении флаттера для использования карты Google. У меня есть пользовательский значок маркера, и я загружаю его с помощью BitmapDescriptor.fromAsset("images/car.png"), однако размер моего значка на карте слишком велик. Я хочу уменьшить его, но не смогнайти любую опцию для этого есть какая-либо опция, чтобы изменить пользовательский значок маркера.вот мой код трепетания:

mapController.addMarker(
        MarkerOptions(
          icon: BitmapDescriptor.fromAsset("images/car.png"),

          position: LatLng(
            deviceLocations[i]['latitude'],
            deviceLocations[i]['longitude'],
          ),
        ),
      );

А вот скриншот моего эмулятора Android:

Как вы можете видеть на картинке мой пользовательский значокразмер слишком большой

Ответы [ 11 ]

0 голосов
/ 31 июля 2019

Я добавлю решение, смешивающее несколько идей и кодов из любого места, чтобы решить эту проблему, сначала функцию для управления размером изображения:

Future<Uint8List> getBytesFromCanvas(double escala, urlAsset) async {

  final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
  final Canvas canvas = Canvas(pictureRecorder);

  final ByteData datai = await rootBundle.load(urlAsset);
  var imaged = await loadImage(new Uint8List.view(datai.buffer));

  double width = ((imaged.width.toDouble() * escala).toInt()).toDouble();
  double height = ((imaged.height.toDouble() * escala).toInt()).toDouble();

  canvas.drawImageRect(imaged, Rect.fromLTRB(0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
                              Rect.fromLTRB(0.0, 0.0, width, height),
                              new Paint(),
  );

  final img = await pictureRecorder.endRecording().toImage(width.toInt(), height.toInt());
  final data = await img.toByteData(format: ui.ImageByteFormat.png);
  return data.buffer.asUint8List();

}

Future < ui.Image > loadImage(List < int > img) async {
  final Completer < ui.Image > completer = new Completer();
  ui.decodeImageFromList(img, (ui.Image img) {

    return completer.complete(img);
  });
  return completer.future;
}

Затем примените эту функцию в зависимости от устройства IOS или Android.Функция getBytesFromCanvas () принимает два параметра: реальный размер изображения и URL ресурса.

var iconTour;

bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
if (isIOS){

  final markerIcon = await getBytesFromCanvas(0.7, 'images/Icon.png');
  iconTour = BitmapDescriptor.fromBytes(markerIcon);

}
else{

  final markerIcon = await getBytesFromCanvas(1, 'images/Icon.png');
  iconTour = BitmapDescriptor.fromBytes(markerIcon);

}

setState(() {
  final Marker marker = Marker(icon: iconTour);
});

Thats all.

0 голосов
/ 21 августа 2019

Я нашел самый простой способ решить эту проблему.

Я использовал приведенную ниже версию для реализации карты Google.В нижней версии карты Google BitmapDescriptor.fromBytes не работает.

 google_maps_flutter: ^0.5.19

И установите маркерные точки, такие как

Future setMarkersPoint() async {
  var icon = 'your url';
  Uint8List dataBytes;
  var request = await http.get(icon);
  var bytes = await request.bodyBytes;

  setState(() {
    dataBytes = bytes;
  });

  final Uint8List markerIcoenter code heren =
      await getBytesFromCanvas(150, 150, dataBytes);

  var myLatLong = LatLng(double.parse(-6.9024812),
      double.parse(107.61881));

  _markers.add(Marker(
    markerId: MarkerId(myLatLong.toString()),
    icon: BitmapDescriptor.fromBytes(markerIcon),
    position: myLatLong,
   infoWindow: InfoWindow(
     title: 'Name of location',
    snippet: 'Marker Description',
   ),
  ));

}

И если вы хотите изменить размер значказатем используйте следующий код.

Future<Uint8List> getBytesFromCanvas(
  int width, int height, Uint8List dataBytes) async {
final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint = Paint()..color = Colors.transparent;
final Radius radius = Radius.circular(20.0);
canvas.drawRRect(
    RRect.fromRectAndCorners(
      Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
      topLeft: radius,
      topRight: radius,
      bottomLeft: radius,
      bottomRight: radius,
    ),
    paint);

var imaged = await loadImage(dataBytes.buffer.asUint8List());
canvas.drawImageRect(
  imaged,
  Rect.fromLTRB(
      0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
  Rect.fromLTRB(0.0, 0.0, width.toDouble(), height.toDouble()),
  new Paint(),
);

    final img = await pictureRecorder.endRecording().toImage(width, height);
    final data = await img.toByteData(format: ui.ImageByteFormat.png);
    return data.buffer.asUint8List();
 }

    Future<ui.Image> loadImage(List<int> img) async {
    final Completer<ui.Image> completer = new Completer();
    ui.decodeImageFromList(img, (ui.Image img) {
  return completer.complete(img);
});
return completer.future;
}

enter image description here

Надеюсь, это сработает для вас .. !!

0 голосов
/ 11 июня 2019

У меня та же проблема, и я решаю этот путь.

Future < Uint8List > getBytesFromCanvas(int width, int height, urlAsset) async 
{
    final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
    final Canvas canvas = Canvas(pictureRecorder);
    final Paint paint = Paint()..color = Colors.transparent;
    final Radius radius = Radius.circular(20.0);
    canvas.drawRRect(
        RRect.fromRectAndCorners(
            Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
            topLeft: radius,
            topRight: radius,
            bottomLeft: radius,
            bottomRight: radius,
        ),
        paint);

    final ByteData datai = await rootBundle.load(urlAsset);

    var imaged = await loadImage(new Uint8List.view(datai.buffer));

    canvas.drawImage(imaged, new Offset(0, 0), new Paint());

    final img = await pictureRecorder.endRecording().toImage(width, height);
    final data = await img.toByteData(format: ui.ImageByteFormat.png);
    return data.buffer.asUint8List();
}

Future < ui.Image > loadImage(List < int > img) async {
    final Completer < ui.Image > completer = new Completer();
    ui.decodeImageFromList(img, (ui.Image img) {

        return completer.complete(img);
    });
    return completer.future;
}

И вы можете использовать вот так.

final Uint8List markerIcond = await getBytesFromCanvas(80, 98, urlAsset);

setState(() {

    markersMap[markerId] = Marker(
        markerId: MarkerId("marker_${id}"),
        position: LatLng(double.parse(place.lat), double.parse(place.lng)),

        icon: BitmapDescriptor.fromBytes(markerIcond),
        onTap: () {
            _onMarkerTapped(placeRemote);
        },

    );
});
0 голосов
/ 21 июня 2019

Я обновил функцию выше, теперь вы можете масштабировать изображение, как вам нравится.

  Future<Uint8List> getBytesFromCanvas(int width, int height, urlAsset) async {
    final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
    final Canvas canvas = Canvas(pictureRecorder);

    final ByteData datai = await rootBundle.load(urlAsset);
    var imaged = await loadImage(new Uint8List.view(datai.buffer));
    canvas.drawImageRect(
      imaged,
      Rect.fromLTRB(
          0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
      Rect.fromLTRB(0.0, 0.0, width.toDouble(), height.toDouble()),
      new Paint(),
    );

    final img = await pictureRecorder.endRecording().toImage(width, height);
    final data = await img.toByteData(format: ui.ImageByteFormat.png);
    return data.buffer.asUint8List();
  }
0 голосов
/ 13 мая 2019

Что сработало для меня, чтобы выбрать правильное изображение для разных плотностей:

MediaQueryData mediaQueryData = MediaQuery.of(context);
ImageConfiguration imageConfig = ImageConfiguration(devicePixelRatio: mediaQueryData.devicePixelRatio);
BitmapDescriptor.fromAssetImage(imageConfig, "assets/images/marker.png");
0 голосов
/ 11 июня 2019

TL; DR : Пока вы можете закодировать любое изображение в необработанных байтах , таких как Uint8List, вы можете использовать в качестве маркера.


На данный момент вы можете использовать данные Uint8List для создания маркеров с помощью Google Maps.Это означает, что вы можете использовать необработанные данные для рисования того, что вы хотите в качестве маркера карты, при условии, что вы сохраняете правильный формат кодирования (который в данном конкретном сценарии является png).

Я рассмотрю два примера, в которых вы можете либо:

  1. Выбрать локальный ресурс и динамически изменить его размер на любой, какой вы пожелаете, и отобразить его на карте (изображение логотипа Flutter);
  2. Нарисуйте некоторые вещи на холсте и визуализируйте их как маркер, но это может быть любой виджет рендеринга.

Кроме того, вы можете даже трансформировать рендервиджет в статическом изображении и, следовательно, использовать его как маркер.


1.Использование актива

Сначала создайте метод, который обрабатывает путь к активу и получает размер (это может быть либо ширина, высота, либо и то и другое, но использование только одного из них сохранит соотношение).

import 'dart:ui' as ui;

Future<Uint8List> getBytesFromAsset(String path, int width) async {
  ByteData data = await rootBundle.load(path);
  ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
  ui.FrameInfo fi = await codec.getNextFrame();
  return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
}

Затем просто добавьте его на карту, используя правильный дескриптор:

final Uint8List markerIcon = await getBytesFromAsset('assets/images/flutter.png', 100);
final Marker marker = Marker(icon: BitmapDescriptor.fromBytes(markerIcon));

Это даст следующее для ширины 50, 100 и 200 соответственно.

asset_example


2.Использование canvas

Вы можете нарисовать что угодно с помощью canvas, а затем использовать его в качестве маркера.Далее будет получен простой скругленный прямоугольник с текстом Hello world!.

Итак, сначала нарисуйте некоторые вещи, используя холст:

Future<Uint8List> getBytesFromCanvas(int width, int height) async {
  final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
  final Canvas canvas = Canvas(pictureRecorder);
  final Paint paint = Paint()..color = Colors.blue;
  final Radius radius = Radius.circular(20.0);
  canvas.drawRRect(
      RRect.fromRectAndCorners(
        Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
        topLeft: radius,
        topRight: radius,
        bottomLeft: radius,
        bottomRight: radius,
      ),
      paint);
  TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
  painter.text = TextSpan(
    text: 'Hello world',
    style: TextStyle(fontSize: 25.0, color: Colors.white),
  );
  painter.layout();
  painter.paint(canvas, Offset((width * 0.5) - painter.width * 0.5, (height * 0.5) - painter.height * 0.5));
  final img = await pictureRecorder.endRecording().toImage(width, height);
  final data = await img.toByteData(format: ui.ImageByteFormat.png);
  return data.buffer.asUint8List();
}

, а затем используйте его таким же образом., но на этот раз, предоставляя любые данные, которые вы хотите (например, ширину и высоту) вместо пути актива.

final Uint8List markerIcon = await getBytesFromCanvas(200, 100);
final Marker marker = Marker(icon: BitmapDescriptor.fromBytes(markerIcon));

и вот, у вас есть.

canvas_example

0 голосов
/ 13 мая 2019

Попробуйте BitmapDescriptor.fromAssetImage.Также будет игнорироваться размер изображения.

BitmapDescriptor.fromAssetImage(
            ImageConfiguration(size: Size(32, 32)), 'assets/car.png')
        .then((onValue) {
      setState(() {
        markerIcon = onValue;
      });
    });

Также использование конфигурации по умолчанию не удается.

loadMarkerImage(BuildContext context) {
    var config = createLocalImageConfiguration(context, size: Size(30, 30));
    BitmapDescriptor.fromAssetImage(config, 'assets/car.png')
        .then((onValue) {
      setState(() {
        markerIcon = onValue;
      });
    });
  }
0 голосов
/ 01 апреля 2019

BitmapDescriptor.fromAsset () - это правильный способ добавления маркеров с одной открытой ошибкой, которая влияет на ваш код.Как ответил Саед, вам нужно предоставить разные размеры изображения для разных плотностей экрана устройства.Исходя из предоставленного вами изображения, я бы предположил, что базовый размер требуемого изображения будет около 48 пикселей.Таким образом, вам нужно будет делать копии размером 48, 96 (2.0x) и 144 (3.0x).

Время выполнения должно выбрать правильное в зависимости от плотности экрана.См. https://flutter.dev/docs/development/ui/assets-and-images#declaring-resolution-aware-image-assets.

В настоящее время это не выполняется автоматически на Android или Fuschia.Если вы выпускаете сейчас и хотите обойти это, вы можете проверить платформу, используя следующую логику:

    MediaQueryData data = MediaQuery.of(context);
    double ratio = data.devicePixelRatio;

    bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;

Если платформа не iOS, вы бы внедрили сегменты в свой код.Объединяя логику в один метод:

String imageDir(String prefix, String fileName, double pixelRatio, bool isIOS) {
    String directory = '/';
    if (!isIOS) {
        if (pixelRatio >= 1.5) {
            directory = '/2.0x/';
        }
        else if (pixelRatio >= 2.5) {
            directory = '/3.0x/';
        }
        else if (pixelRatio >= 3.5) {
            directory = '/4.0x/';
        }
    }
    return '$prefix$directory$fileName';
}

Затем вы можете создать маркер для значка с именем person_icon в каталоге ресурсов ** assets / map_icons / ** с этим кодом, используяметод:

            myLocationMarker = Marker(
            markerId: MarkerId('myLocation'),
            position: showingLocation, flat: true,
            icon: BitmapDescriptor.fromAsset(imageDir('assets/map_icons','person_icon.png', ratio, isIos)));
0 голосов
/ 23 января 2019

Следует избегать больших изображений, так как они занимают ненужное место.Изображения должны быть масштабированы для вашей карты, с вариациями разрешения в пикселях, чтобы соответствовать устройству.

Например, базовое изображение должно быть масштабировано до правильного размера за пределами вашего приложения.Разные устройства имеют разное разрешение пикселей, которое развевается.Требуется другая версия вашего изображения, чтобы изображение не казалось неровным.Увеличьте изображение для разных разрешений.то есть базовая версия 32x32 пикселей, версия 2.0 будет 64x64 пикселей, версия 3.0 будет 128x128 и т. д. См. описанный ниже стандартный способ флаттера, который учитывает различные разрешения пикселей в зависимости от производителя устройства.

BitmapDescriptor.fromAsset не поддерживает автоматическое декодирование разрешения в пикселях и загружает файл, указанный в пути.Чтобы исправить этот вызов AssetImage для декодирования правильного имени файла.

Существует ошибка при рендеринге изображений, изображения в iOS выглядят больше, чем в Android, см. Дефект 24865 .Для этого тоже есть обходной путь, путем жесткого кодирования имени файла разрешения, которое вы бы предпочли.

В следующих разделах описан стандартный способ флаттера , обходной путь AssetImage и обходной путь 24865 .

Стандартные соглашения об именах изображений Flutter

Создайте папку ресурсов с соглашением об именах :

pathtoimages/image.png
pathtoimages/Mx/image.png
pathtoimages/Nx/image.png
pathtoimages/etc.

Где M и N - разрешения (2,0x) илитемы (темные).Затем добавьте изображение или все изображения в файл pubspec.file в виде

flutter:
  assets:
    - pathtoimages/image.png

или

flutter:
  assets:
    - pathtoimages/

Обходной путь для Карт Google

Этот стандарт требует, чтобы изображения затем загружались с использованием AssetImage ('pathtoimages / image.png'), которое не поддерживается плагином карт Google.Карты Google требуют, чтобы вы использовали BitmapDescriptor.fromAsset ('pathtoimages / image.png'), который в настоящее время не разрешает правильное изображение.Чтобы исправить это использование, вы можете получить правильное изображение из AssetImage, сначала создав createLocalImageConfiguration, используя BuildContext, как определено здесь .Затем используйте эту конфигурацию для разрешения правильного изображения следующим образом:

ImageConfiguration config = createLocalImageConfiguration(context);
AssetImage('pathtoimages/image.png')
   .obtainKey(config)
   .then((resolvedImage) {
       print('Name: ' + resolvedImage.onValue.name);
    });

Дефект 24865 Обходной путь

 BitmapDescriptor get deliveryIcon {
      bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
          If (isIOS)
              return BitmapDescriptor.fromAsset('pathtoimages/image.png');
         else
              return BitmapDescriptor.fromAsset(
              resolvedImageName);
    }
0 голосов
/ 21 января 2019

Простой способ, который я нашел, чтобы решить это, это просто

BitmapDescriptor get deliveryIcon {
  bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
  if (isIOS)
    return BitmapDescriptor.fromAsset('assets/icons/orange_pin.png');
  else
    return BitmapDescriptor.fromAsset(
        'assets/icons/3.0x/orange_pin.png');
} 

Проще говоря, поставьте андроиду больший актив.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...