Optimize custom clippers inside InteractiveViewer

109 Views Asked by At

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

Gif of how the app looks

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.

0

There are 0 best solutions below