My goal:
- Create an interactive map in flutter
- User should be able to pan around in the map
- User should be able to click on different countries in the map
- When user click's on a country, the country changes color
- The app should run at reasonable framerate even on weaker phones
I have the first four points implemented, however, I am struggling with making it run smoothly. I am using custom clippers for each country.
The question
Can I speed Clippers up? If not, what are some alternatives to Clippers that still let me do the first four requirements? I would prefer to use flutter, but I am open to any technology that let's me develop for iOS and Android at the same time.
Current implementation
The important points are:
- I am using
InteractiveViewer
to allow movement in the map. - Each country is represented by Clipper with a touch control and container inside.
I don't think the code is that important but it still might be usefull to someone, so I am posting it below.
First, there is the wrapper that puts everything into InteractiveViewer
class MapWrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: InteractiveViewer(
constrained: false,
child: MapContent(),
),
);
}
}
Then, there is MapContent:
class MapContent extends StatelessWidget {
List<Widget> buildMap(List<MapItem> mapItems) {
List<Widget> result = [];
for (final item in mapItems) {
result.add(
ClipPath(
clipper: item.clipper,
child: GestureDetector(
onTap: handleTap,
child: Container(
color: item.color,
// this is not the best way to make sure container covers the whole clipper, I am pretty new to flutter and just want to get a prototype running first.
width: item.clipper.getBounds().width +
item.clipper.getBounds().left,
height: item.clipper.getBounds().height +
item.clipper.getBounds().top,
),
)),
);
}
return result;
}
@override
Widget build(BuildContext context) {
MapData map = MapData("assets/cz-05.svg");
return Stack(
children: buildMap(map .getItems()),
);
}
}
And the MapData with MapItem
class MapItem {
MapItem(this.clipper, this.name, this.color);
SvgClipper clipper;
String name;
Color color;
}
class MapData {
MapData(String filePath)
: _items = loadItems() // static method that just loads all <path> from svg (see below);
List<MapItem> _items;
List<MapItem> getItems() {
return _items;
}
}
and finally, I am using data from here, for example this czech map.