Когда дело доходит до отображения карт в приложении Flutter, есть два основных варианта. Вы можете либо использовать flutter_map
реализацию Leaflet для Flutter, которая будет работать с рядом бесплатных и платных поставщиков карт, либо использовать, google_maps_flutter
если хотите, более популярные Google Карты.
Я буду использовать этот пост в блоге google_maps_flutter
, который создан и поддерживается командой Flutter в Google.
Если вы используете Google Карты впервые, я рекомендую проверить кодовую метку Google для карт в Flutter. Мне нужно было нарисовать несколько пользовательских маркеров, таких как те, что на изображении ниже.
Вы можете ожидать, что вы можете передать Widget
для маркера, так же, как при использовании чего-либо еще во Флаттере. Но это не так просто, как Marker
принять BitmapDescriptor
за иконку. Я собираюсь объяснить, как вы можете этого достичь.
Что это BitmapDescriptor
? Если вы когда-либо работали с родным SDK Google Maps для iOS или Android, это вас не удивит.
BitmapDescriptor
это объект, который определяет растровое изображение, которое затем может быть использовано Google Maps для рисования на карте. Он используется на обеих платформах, и это единственный способ добавить пользовательские значки для маркеров. Итак, это ограничение исходит от родного SDK Google Maps, который google_maps_flutter
использует, так как пока нет полной реализации трепетания для сложного виджета, такого как карты.
BitmapDescriptor
примет изображение актива или растровое изображение. В нашем случае текст маркера является динамическим, поэтому статическое изображение ресурса не подходит. Что касается растрового изображения, в нативном Android / iOS есть способ преобразовать ваше View
в Bitmap
(или UIView
в UIImage
), и вы можете передать это BitmapDescriptor
.
Вы можете сделать то же самое во Флаттере, но это немного сложнее. Главным образом потому, что вы не можете надуть / загрузить виджет где-то на стороне и преобразовать его в растровое изображение. Вам нужно нарисовать виджет в иерархии представления экрана и затем извлечь его нарисованное растровое изображение.
Главное, что вам нужно знать, это то, что каждый из Widget
них больше похож на класс данных, и вы RenderObject
получаете доступ к растровому изображению в его связанном , которое создается на этапе сборки.
RenderObject
Нарисуйте свой виджет на экране. Это из метода сборки некоторых виджетов, который будет раздувать наши маркеры. Мы используем, GlobalKey
поэтому у нас есть ссылка на этот виджет после его создания.
final markerKey = GlobalKey();
return RepaintBoundary(
key: markerKey,
child: customMarkerWidget,
);
Теперь вы можете GlobalKey
использовать это после создания виджета:
markerKey.currentContext.findRenderObject();
Uint8List
в основном это список целых чисел без знака, который представляет растровое изображение в этом случае, так как в дротике нет специального растрового класса. BitmapDescriptor
также будет принимать , Uint8List
так что нам нужно сделать некоторые преобразования , чтобы получить от RenderObject
до Uint8List
. У меня есть все это в следующем методе:
Future<Uint8List> getUint8List(GlobalKey markerKey) async {
RenderRepaintBoundary boundary =
markerKey.currentContext.findRenderObject();
var image = await boundary.toImage(pixelRatio: 2.0);
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData.buffer.asUint8List();
}
Я показал вам, как получить RenderObject
и преобразовать его Uint8List
, но когда вы вызываете этот метод?
Нам нужно получить наши растровые изображения сразу после их отрисовки. Есть несколько способов сделать это, я использую крошечные AfterLayoutMixin
.
@
override
void
afterFirstLayout
(
BuildContext
context
) {
getUint8List(markerKey).then((markerBitmap) =>
// Set state and use your markerBitmap
);
}
Там у вас есть это. Создайте Marker
с Uint8List
и вставьте его в Google Map:
Marker(
position: position,
icon: BitmapDescriptor.fromBytes(markerUint8List)
)
Вы должны получить что-то вроде этого:
Я извлек все это в одном простом в использовании классе MarkerGenerator
. Это немного более продвинуто, чем руководство, объясненное здесь. Он использует overlay
маркер для создания виджетов и обеспечивает List<Uint8List>
обратный вызов.
Скопируйте его в свой проект. Тогда вы используете MarkerGenerator
этот способ:
@override void initState() {
super.initState();
MarkerGenerator(markerWidgets, (bitmaps) {
setState(() {
markers = mapBitmapsToMarkers(bitmaps);
});
}).generate(context);
}
При работе во Flutter некоторые вещи занимают больше времени, чем написание их на родном Android / iOS, как это произошло на этот раз с пользовательскими маркерами карты. Но в целом я считаю, что Flutter определенно экономит время и является отличным выбором для большинства приложений.