Flutter地图操作与展示插件mapster的使用

Flutter 地图操作与展示插件mapster的使用

Mapster 是一个对象映射库。

如何使用

步骤 1: 扩展一个 Mapper

你可以扩展 Mapper 类来实现从一个或多个源对象到目标对象的映射。例如,如果你只需要将一个对象映射到另一个对象,那么可以扩展 OneSourceMapper

class UserToUserResponseMapper extends OneSourceMapper<User, UserResponse> {
  UserToUserResponseMapper(super.input);

  @override
  UserResponse map() {
    return UserResponse(
      id: source.id,
      fullName: '${source.firstName} ${source.lastName}',
    );
  }
}

步骤 2: 创建 Mapster 实例

创建一个 Mapster 实例来管理你的映射器。

void main() {
  final mapster = Mapster();
}

步骤 3: 注册所有映射器

在创建的 Mapster 实例中注册你所有的映射器。根据映射器类型(如 OneSourceMapper, TwoSourcesMapper 等),使用 MapperMeta 的静态方法进行注册。

void main() {
  final mapster = Mapster();

  mapster.register(MapperMeta.one(UserToUserResponseMapper.new));
}

步骤 4: 使用 Mapster

最后,你可以使用 Mapster 来执行映射操作。

void main() {
  final mapster = Mapster();

  mapster.register(MapperMeta.one(UserToUserResponseMapper.new));

  const user = User(
    id: 1,
    firstName: 'Harry',
    lastName: 'Potter',
  );

  final userResponse = mapster.map1(user, To<UserResponse>());

  print(userResponse);
}

注意,你需要传递 To<YourResultType>() 作为最后一个参数。这指定了 Mapster 应该返回的类型。

你还可以为源对象创建私有 getter,这样会更方便。

class UserUserPostToLikedPostNotification
    extends ThreeSourcesMapper<User, User, Post, LikedPostNotification> {
  UserUserPostToLikedPostNotification(super.input);

  @override
  LikedPostNotification map() {
    return LikedPostNotification(
      postID: _post.id,
      authorID: _user1.id,
      likeUserID: _user2.id,
      postText: _post.text,
      authorName: '${_user1.firstName} ${_user1.lastName}',
      likeUserName: '${_user2.firstName} ${_user2.lastName}',
    );
  }

  User get _user1 => source1;

  User get _user2 => source2;

  Post get _post => source3;
}

映射函数

Mapster 提供了九种映射方法:map1, map2, …, map9。这些方法接受源对象并指定输出类型。

你可以以任何顺序传递源对象给 Mapster 的映射方法。你不需要检查特定映射器的输入对象顺序。Mapster 足够智能,可以找到合适的映射器。

class UserPostToPostResponse extends TwoSourcesMapper<User, Post, PostResponse> {
  UserPostToPostResponse(super.input);

  @override
  PostResponse map() {
    return PostResponse(
      id: source2.id,
      text: source2.text,
      userID: source1.id,
      userName: '${source1.firstName} ${source1.lastName}',
    );
  }
}

void main() {
  final mapster = Mapster();

  mapster.register(MapperMeta.two(UserPostToPostResponse.new));

  const user = User(
    id: 1,
    firstName: 'Harry',
    lastName: 'Potter',
  );

  const post = Post(
    id: 1,
    text: "The philosopher's stone",
  );

  // 你可以交换源对象,结果将是相同的。
  final postResponse1 = mapster.map2(user, post, To<PostResponse>());
  final postResponse2 = mapster.map2(post, user, To<PostResponse>());

  print(postResponse1);
  print(postResponse2);
}

注意,对于具有多个相同类型源对象的映射器,Mapster 会按照传递的顺序匹配输入对象。因此,如果交换多个相同类型的对象,结果可能会改变。

class UserUserPostToLikedPostNotification
    extends ThreeSourcesMapper<User, User, Post, LikedPostNotification> {
  UserUserPostToLikedPostNotification(super.input);

  @override
  LikedPostNotification map() {
    return LikedPostNotification(
      postID: source3.id,
      authorID: source1.id,
      likeUserID: source2.id,
      postText: source3.text,
      authorName: '${source1.firstName} ${source1.lastName}',
      likeUserName: '${source2.firstName} ${source2.lastName}',
    );
  }
}

void main() {
  final mapster = Mapster();

  mapster.register(MapperMeta.three(UserUserPostToLikedPostNotification.new));

  const user = User(
    id: 1,
    firstName: 'Harry',
    lastName: 'Potter',
  );

  const post = Post(
    id: 1,
    text: "The philosopher's stone",
  );

  const likeUser = User(
    id: 2,
    firstName: 'Ronald',
    lastName: 'Weasley',
  );

  // 你可以交换源对象,但如果交换多个相同类型的对象,结果将会改变。
  final notification1 = mapster.map3(
    user,
    likeUser,
    post,
    To<LikedPostNotification>(),
  );
  final notification2 = mapster.map3(
    likeUser,
    user,
    post,
    To<LikedPostNotification>(),
  );

  print(notification1);
  print(notification2);
}

优点与缺点

优点

  • 不需要在使用 registermap 函数时指定类型。
  • 不需要担心参数顺序。
  • 分析器能正确确定 map 函数的返回类型。
  • Mapster 查找合适映射器的时间复杂度为 O(1)。
  • Mapster 在传递参数之前对参数进行排序的时间复杂度为 O(n),其中 n 是参数的数量。
  • Mapster 没有依赖。
  • 不再需要通过大量映射器注入类/函数,只需注入 Mapster
  • 不需要知道具体的映射器来进行映射。
  • 可以在一个地方指定映射器。
  • 可以重新定义映射器。

缺点

  • 目前尚未发现。

其他特性

重新定义映射器

你可以通过再次调用 register 方法来重新定义映射器。

void main() {
  final mapster = Mapster();

  const user = User(
    id: 1,
    firstName: 'Harry',
    lastName: 'Potter',
  );

  // 注册映射器,输入类型为 User,输出类型为 UserResponse。
  mapster.register(MapperMeta.one(UserToUserResponseMapper.new));

  final userResponse1 = mapster.map1(user, To<UserResponse>());

  // 注册另一个映射器,输入类型和输出类型相同:
  // 输入类型为 User,输出类型为 UserResponse。
  mapster.register(MapperMeta.one(AnotherUserToUserResponseMapper.new));

  final userResponse2 = mapster.map1(user, To<UserResponse>());
}

Mapster 根据其源类型和结果类型存储映射器。如果新的映射器具有与旧映射器相同的输入类型集(输入类型顺序无关紧要)和相同的输出类型,则 Mapster 将用新映射器替换旧映射器。

void main() {
  final mapster = Mapster();

  const user = User(
    id: 1,
    firstName: 'Harry',
    lastName: 'Potter',
  );

  // 注册映射器,输入类型为 User,输出类型为 UserResponse。
  mapster.register(MapperMeta.one(UserToUserResponseMapper.new));

  final userResponse1 = mapster.map1(user, To<UserResponse>());

  // 注册另一个映射器,输入类型和输出类型交换:
  // 输入类型为 UserResponse,输出类型为 User。
  mapster.register(MapperMeta.one(UserResponseToUserMapper.new));

  // 因为第一个映射器的输入类型集包含不同的类型,而第二个映射器的输入类型集不同,
  // 这两个映射器被认为是不同的。
  // 我们也可以这样说:因为第一个映射器的输出类型不等于第二个映射器的输出类型,
  // 这两个映射器被认为是不同的。
  final user2 = mapster.map1(userResponse1, To<User>());
}

与 injectable 集成

如果你使用 injectable 包,你可以像这样注册 Mapster 和映射器:

[@module](/user/module)
abstract class MapsterModule {
  [@singleton](/user/singleton)
  Mapster get mapster => Mapster();
}

[@singleton](/user/singleton)
class MapsterRegistrar {
  const MapsterRegistrar(this._mapster);

  final Mapster _mapster;

  [@postConstruct](/user/postConstruct)
  void register() {
    _mapster
      ..register(MapperMeta.one(UserToUserResponseMapper.new))
      ..register(MapperMeta.three(UserUserPostToLikedPostNotification.new));
  }
}

更多关于Flutter地图操作与展示插件mapster的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地图操作与展示插件mapster的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,mapster 插件虽然不是一个广泛认知的官方或主流地图插件(如 flutter_mapgoogle_maps_flutter),但假设它是一个用于地图操作和展示的第三方库,我们可以通过一些假设性的代码案例来展示如何使用它(请注意,以下代码是基于假设的 mapster 插件的API)。

首先,确保你已经在 pubspec.yaml 文件中添加了 mapster 依赖项(请注意,这里的依赖项名称是假设的,实际使用时需要替换为真实的插件名称):

dependencies:
  flutter:
    sdk: flutter
  mapster: ^x.y.z  # 替换为实际的版本号

然后,运行 flutter pub get 来获取依赖项。

接下来是一个基本的代码示例,展示如何在Flutter应用中使用 mapster 插件来显示和操作地图:

import 'package:flutter/material.dart';
import 'package:mapster/mapster.dart';  // 假设的导入路径

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Mapster Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MapScreen(),
    );
  }
}

class MapScreen extends StatefulWidget {
  @override
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  MapsterController? _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Mapster Demo'),
      ),
      body: MapsterMap(
        controller: _controller,
        initialCameraPosition: CameraPosition(
          target: LatLng(37.7749, -122.4194), // 旧金山
          zoom: 12.0,
        ),
        onMapCreated: (MapsterController controller) {
          _controller = controller;
          // 可以在这里添加地图标记、多边形等
          _addMarker();
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 示例:移动到新的位置
          _controller?.animateCamera(
            CameraUpdate.newLatLngZoom(LatLng(40.7128, -74.0060), 14.0),
          ); // 纽约
        },
        tooltip: 'Move to New York',
        child: Icon(Icons.location_searching),
      ),
    );
  }

  void _addMarker() {
    if (_controller != null) {
      _controller!.addMarker(
        MarkerOptions(
          position: LatLng(37.7749, -122.4194),
          infoWindow: InfoWindow(title: 'San Francisco'),
          icon: BitmapDescriptor.defaultMarker,
        ),
      );
    }
  }
}

在这个示例中,我们做了以下几件事:

  1. 导入 mapster 包。
  2. 创建一个基本的 Flutter 应用。
  3. MapScreen 中使用 MapsterMap 小部件来显示地图。
  4. 使用 MapsterController 来控制地图,例如添加标记和移动相机位置。
  5. 在地图创建完成后,通过 onMapCreated 回调获取 MapsterController 实例,并添加一个标记。
  6. 提供一个浮动操作按钮来演示如何移动地图相机到新的位置。

请注意,由于 mapster 并非一个真实存在的Flutter插件(据我所知),上述代码是基于假设的API设计的。如果你正在使用一个具体的地图插件,请参考该插件的官方文档和API参考来编写实际代码。对于真实存在的插件,如 flutter_mapgoogle_maps_flutter,它们的用法会有所不同,但基本的概念(如地图显示、标记添加、相机控制等)是相似的。

回到顶部