效果展示(这里只展示局部,完全展示违规):
可以点击省份改变颜色,更多功能可以自行拓展。
注:非完整中国地图!!!
本文用于记录在Flutter项目中安卓端实现中国地图,因为实现过程是通过Flutter调用安卓原生代码实现,所以IOS端不可用,通过本文你还可以学会如何通过Platform Channels在Flutter代码中调用这些原生代码。
在Flutter中打开android文件夹
右键android 文件夹,选择flutter -> Open Android module in Android Studio
点击后就会像打开一个纯Android项目一样(当然还是有些差别的,多了些Flutter相关东西),在这个界面中可以编写原生代码和相应插件。
如果你是第一次打开,它会下载gradle和一大堆构建项目需要的东西,要等好长一会(这个时候你可以买杯咖啡等它构建完成:)),当然过程可能不是那么的顺利,比如你下载gradle过程中会报下面错误(如果没有则忽略下面步骤):
gradle Connect timed out
方法一:
然后我就尝试修改仓库配置为阿里镜像:
allprojects {
repositories {
google()
maven { url "https://jitpack.io" }
mavenCentral()
maven { url "https://maven.aliyun.com/repository/public" } //jcenter & central
}
}
结果还是一样,科学上网打开也一样,此方法无效!
方法二:
在https://services.gradle.org/distributions/ 网址中找到你项目中对应的Gradle版本并下载下来。
解压下载的文件并将其放到你的C:/Users/{用户名}/.gradle/wrapper/dists/gradle-{版本号}-all/{随机字符串}
目录下。
如果你不确定应该下载哪个版本的Gradle,你可以查看你的Android工程中的gradle/wrapper/gradle-wrapper.properties文件,该文件中的distributionUrl属性就是你需要的Gradle版本。
可能你的.gradle文件夹移到别的地方了,毕竟这个文件夹占用内存太大,正经人谁放C盘 :)
就算是下载超时,本地文件也会创建.gradle/wrapper/dists/gradle-{版本号}-all/{随机字符串}
这个目录的。
此时再Build就可以了,接下来就是大量时间去下载其他依赖…
至此Gradle下载问题解决。
不出意外的话接下来你还会遇到这个问题:
Multiple build operations failed.
Could not create task ':flutter_plugin_android_lifecycle:generateDebugUnitTestConfig'.
Could not create task ':image_picker_android:generateDebugUnitTestConfig'.
Could not create task ':path_provider_android:generateDebugUnitTestConfig'.
Could not create task ':shared_preferences_android:generateDebugUnitTestConfig'.
Could not create task ':video_player_android:generateDebugUnitTestConfig'.
Could not create task ':wakelock_plus:generateDebugUnitTestConfig'.
Could not create task ':flutter_plugin_android_lifecycle:generateDebugUnitTestConfig'.
this and base files have different roots: D:\resource\td_ecology_v1\build\flutter_plugin_android_lifecycle and C:\Users\xx\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\flutter_plugin_android_lifecycle-2.0.17\android.
不要慌,解决方法如下:
在文件[flutter项目]\android\build.gradle中,注释掉一行代码就行。
rootProject.buildDir = '../build'
subprojects {
//project.buildDir = "${rootProject.buildDir}/${project.name}" // 把这行注释掉,在flutter运行的时候,记得取消这行的注释
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
注释后再Build就可以构建完成了,记得在Flutter运行的时候,记得取消这行的注释哦,不然会报下面错误:
Exception: Gradle build failed to produce an .apk file. It's likely that this file was generated under D:\resource\xxx\build, but the tool couldn't find it.
原生代码编写
核心代码传到了CSDN资源里面,自行下载,不要积分:core文件夹
里面的xml文件要放到 android\app\src\main\res\raw
文件夹下奥。
目录如下图所示:
接下来就是在MainActivity中加入下面代码:
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
flutterEngine.plugins.add(mutableSetOf<FlutterPlugin>(ChinaProvinceViewFlutterPlugin()))
}
}
然后返回你的Flutter工程添加下面两个文件:
china_province_view.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const _ChinaProvinceView_TAG =
'com.mrper.coronavirus.widgets.china-province-view';
///中国行政区域地图控件
class ChinaProvinceView extends StatefulWidget {
ChinaProvinceView({
required this.width,
required this.onViewCreated,
}) : assert(width != null && width > 0, '地图宽度必须大于0');
/// 地图宽度
final double width;
/// 视图创建完成的事件
final Function(int id) onViewCreated;
_ChinaProvinceViewState createState() => _ChinaProvinceViewState();
}
class _ChinaProvinceViewState extends State<ChinaProvinceView> {
/// 地图的宽高比例
final double _mapWHRatio = 1369.0 / 1141.0;
Widget build(BuildContext context) => SizedBox(
width: widget.width,
height: widget.width / _mapWHRatio,
child: AndroidView(
viewType: _ChinaProvinceView_TAG,
creationParamsCodec: StandardMessageCodec(),
onPlatformViewCreated: widget.onViewCreated));
}
class ChinaProvinceViewController {
late MethodChannel? _methodChannel;
late EventChannel? _eventChannel;
ChinaProvinceViewController(int viewId) {
_methodChannel = MethodChannel('$_ChinaProvinceView_TAG-$viewId');
_eventChannel = EventChannel('$_ChinaProvinceView_TAG-$viewId-event');
}
/// 设置选中的背景色
set selectedBackgroundColor(int value) => _methodChannel?.invokeMethod(
'setSelectedBackgroundColor', {'value': value ?? Colors.red.value});
void dispose() {
if (_methodChannel != null) {
_methodChannel?.setMethodCallHandler(null);
_methodChannel = null;
}
if (_eventChannel != null) {
_eventChannel = null;
}
}
}
map_page.dart
import 'package:ecology/component/app_bar.dart';
import 'package:flutter/material.dart';
import 'china_province_view.dart';
class MapPage extends StatefulWidget {
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
late ChinaProvinceViewController _chinaProvinceViewController;
void _onChinaProvinceViewCreated(int viewId) {
_chinaProvinceViewController = ChinaProvinceViewController(viewId)
..selectedBackgroundColor = Colors.blue.value;
}
Widget build(BuildContext context) => Container(
child: SingleChildScrollView(
child: Column(children: [_buildChinaMapView()])),
);
Widget _buildChinaMapView() {
return Container(
margin: const EdgeInsets.all(5),
child: ChinaProvinceView(
width: MediaQuery.of(context).size.width - 10,
onViewCreated: _onChinaProvinceViewCreated));
}
void dispose() {
_chinaProvinceViewController?.dispose();
super.dispose();
}
}
MapPage
就是地图界面了。
打完收工,又是加班的一天 ┭┮﹏┭┮
该篇文章代码参考自gitee上一个大佬的项目:https://gitee.com/yugecse/coronavirus