Flutter二维地图渲染插件tilemap_2d的使用
Flutter二维地图渲染插件tilemap_2d的使用
简介
tilemap_2d
是一个用于在 Flutter 中渲染二维地图的插件。它允许开发者通过图块(tiles)来加载和显示地图,并支持添加标记层(Marker Layer)和图像层(Image Layer)。
使用示例
以下是一个完整的示例,展示了如何使用 tilemap_2d
插件来创建一个带有标记和图像层的地图应用。
import 'dart:convert';
import 'dart:ui';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart' hide Image;
import 'package:flutter/services.dart';
import 'package:screenshot/screenshot.dart';
import 'package:tilemap_2d/tilemap_2d.dart';
void main() {
runApp(const App());
}
class ScrollBehavior extends MaterialScrollBehavior {
const ScrollBehavior();
[@override](/user/override)
Set<PointerDeviceKind> get dragDevices => PointerDeviceKind.values.toSet();
}
class App extends StatelessWidget {
const App({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
scrollBehavior: ScrollBehavior(),
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
[@override](/user/override)
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
final icons = <String, String>{};
final markers = [];
late final TilemapController controller;
[@override](/user/override)
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
rootBundle.loadString('assets/icons.json').then((json) async {
for (final icon in jsonDecode(json)) {
icons[icon['name']] = icon['url'];
}
json = await rootBundle.loadString('assets/markers.json');
markers.addAll(jsonDecode(json));
addMarkerLayer(0, await getIcon(0), 24, zIndex: 3);
await addDefaultMarkerLayer(1);
await addDefaultMarkerLayer(2);
await addDefaultMarkerLayer(3);
controller.animateTo(
coordinate: const Offset(-6299 + 1427, -1190),
zoom: -2.8,
duration: const Duration(milliseconds: 1200),
);
});
});
}
Future<Image> getIcon(int index) async {
final iconUrl = icons[markers[index][0]['itemList'][0]['iconTag']];
return resolveImage(CachedNetworkImageProvider(iconUrl!));
}
Future<void> addDefaultMarkerLayer(int index) async {
final icon = await getIcon(index);
final screenshot = ScreenshotController();
final imageData = await screenshot.captureFromWidget(
Container(
decoration: const BoxDecoration(
color: Colors.white70,
borderRadius: BorderRadius.all(Radius.circular(30)),
),
child: RawImage(image: icon),
),
delay: Duration.zero,
);
final image = await decodeImageFromList(imageData);
addMarkerLayer(index, image, 30);
}
void addMarkerLayer(int index, Image image, double size, {int zIndex = 2}) {
final markers = this.markers[index];
final items = markers.map((i) {
final position = i['position'].split(',');
return MarkerItem(
Offset(double.parse(position[0]), double.parse(position[1])), i);
}).cast<MarkerItem>();
controller.addLayer(MarkerLayer(
image: image,
items: items.toList(),
scale: size / image.width,
zIndex: zIndex,
));
}
void onMapCreated(TilemapController controller) {
this.controller = controller;
controller.addLayer(TileLayer(
getImageProvider: (x, y, z) => CachedNetworkImageProvider(
'https://assets.yuanshen.site/tiles_twt36/$z/${x}_$y.png',
),
minZoom: 10,
maxZoom: 13,
offset: const Offset(-6144, 0),
));
initNonGroundMaps();
}
void initNonGroundMaps() async {
const images = [
'https://assets.yuanshen.site/overlay/YL/1.png',
'https://assets.yuanshen.site/overlay/YL/2.png',
'https://assets.yuanshen.site/overlay/YL/3.png',
'https://assets.yuanshen.site/overlay/YL/4.png',
'https://assets.yuanshen.site/overlay/YL/5.png',
'https://assets.yuanshen.site/overlay/YL/6.png',
'https://assets.yuanshen.site/overlay/YL/7.png',
'https://assets.yuanshen.site/overlay/YL/8.png',
'https://assets.yuanshen.site/overlay/YL/9.png',
'https://assets.yuanshen.site/overlay/YL/10.png',
'https://assets.yuanshen.site/overlay/YL/11.png',
'https://assets.yuanshen.site/overlay/YL/12.png',
];
const rects = [
[-6299 + 1427, -2190 + 1353, 404, 504],
[-6299 + 1299, -2190 + 2040, 648, 570],
[-6299 + 2199, -2190 + 1671, 398, 306],
[-6299 + 2177, -2190 + 2168, 570, 515],
[-6299 + 2734, -2190 + 937, 433, 660],
[-6299 + 3323, -2190 + 507, 443, 377],
[-6299 + 3426, -2190 + 924, 278, 360],
[-6299 + 3796, -2190 + 1024, 344, 393],
[-6299 + 3563, -2190 + 1604, 443, 799],
[-6299 + 3787, -2190 + 2710, 378, 560],
[-6299 + 3086, -2190 + 3297, 521, 433],
[-6299 + 1887, -2190 + 3637, 740, 346],
];
for (var i = 0; i < images.length; i += 1) {
final rect = rects[i];
await controller.addLayer(
ImageLayer(
zIndex: 1,
image: CachedNetworkImageProvider(images[i]),
rect: Rect.fromLTWH(
rect[0].toDouble(),
rect[1].toDouble(),
rect[2].toDouble(),
rect[3].toDouble(),
),
),
);
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: Tilemap(
size: const Size(18432, 16384),
origin: const Offset(3568 + 6144, 6286),
maxZoom: 0.5,
onCreated: onMapCreated,
onTap: (details) {
final data = details?.markerItem?.data;
if (data != null) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(data['markerTitle']),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (data['content']?.isNotEmpty ?? false)
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(data['content'].replaceAll('\\n', '\n')),
),
if (data['picture']?.isNotEmpty ?? false)
CachedNetworkImage(
imageUrl: data['picture'],
fit: BoxFit.fitWidth,
),
],
),
),
);
},
);
}
},
),
);
}
}
更多关于Flutter二维地图渲染插件tilemap_2d的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter二维地图渲染插件tilemap_2d的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
tilemap_2d
是一个用于在 Flutter 中渲染二维地图的插件。它允许你加载和显示基于瓦片(tile)的地图,通常用于游戏或地理信息系统(GIS)应用中。以下是如何使用 tilemap_2d
插件的基本步骤。
1. 添加依赖
首先,在你的 pubspec.yaml
文件中添加 tilemap_2d
依赖:
dependencies:
flutter:
sdk: flutter
tilemap_2d: ^latest_version
然后运行 flutter pub get
来获取依赖。
2. 导入包
在你的 Dart 文件中导入 tilemap_2d
包:
import 'package:tilemap_2d/tilemap_2d.dart';
3. 创建地图
tilemap_2d
插件允许你加载和显示基于瓦片的地图。你可以使用 TileMap
类来创建地图。
class MyMapWidget extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TileMap 2D Example'),
),
body: Center(
child: TileMap(
tileSize: 32.0, // 每个瓦片的大小
mapSize: Size(10, 10), // 地图的大小(以瓦片为单位)
tiles: [
// 这里定义地图的瓦片
Tile(0, 0, TileType.grass),
Tile(1, 0, TileType.grass),
Tile(2, 0, TileType.water),
// 更多瓦片...
],
),
),
);
}
}
4. 定义瓦片类型
你可以定义不同的瓦片类型,比如草地、水等。通常你会有一个 TileType
枚举来表示不同的瓦片类型。
enum TileType {
grass,
water,
sand,
// 更多类型...
}
5. 加载瓦片图像
你需要为每种瓦片类型加载对应的图像。你可以使用 Image.asset
或 Image.network
来加载图像。
class Tile {
final int x;
final int y;
final TileType type;
Tile(this.x, this.y, this.type);
Widget getTileImage() {
switch (type) {
case TileType.grass:
return Image.asset('assets/grass.png');
case TileType.water:
return Image.asset('assets/water.png');
case TileType.sand:
return Image.asset('assets/sand.png');
default:
return Container();
}
}
}
6. 渲染地图
在 TileMap
中,你可以通过 tiles
属性来传递瓦片列表,并在 TileMap
内部使用 getTileImage
方法来渲染每个瓦片。
TileMap(
tileSize: 32.0,
mapSize: Size(10, 10),
tiles: [
Tile(0, 0, TileType.grass),
Tile(1, 0, TileType.grass),
Tile(2, 0, TileType.water),
// 更多瓦片...
],
)
7. 处理交互
你还可以处理用户与地图的交互,比如点击某个瓦片时触发事件。
TileMap(
tileSize: 32.0,
mapSize: Size(10, 10),
tiles: [
Tile(0, 0, TileType.grass),
Tile(1, 0, TileType.grass),
Tile(2, 0, TileType.water),
// 更多瓦片...
],
onTileTap: (x, y) {
print('Tile tapped at ($x, $y)');
},
)
8. 完整示例
以下是一个简单的完整示例:
import 'package:flutter/material.dart';
import 'package:tilemap_2d/tilemap_2d.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: MyMapWidget(),
);
}
}
enum TileType {
grass,
water,
sand,
}
class Tile {
final int x;
final int y;
final TileType type;
Tile(this.x, this.y, this.type);
Widget getTileImage() {
switch (type) {
case TileType.grass:
return Image.asset('assets/grass.png');
case TileType.water:
return Image.asset('assets/water.png');
case TileType.sand:
return Image.asset('assets/sand.png');
default:
return Container();
}
}
}
class MyMapWidget extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TileMap 2D Example'),
),
body: Center(
child: TileMap(
tileSize: 32.0,
mapSize: Size(10, 10),
tiles: [
Tile(0, 0, TileType.grass),
Tile(1, 0, TileType.grass),
Tile(2, 0, TileType.water),
// 更多瓦片...
],
onTileTap: (x, y) {
print('Tile tapped at ($x, $y)');
},
),
),
);
}
}