Region and path.op() approaches work well, but suffer from a lack of precision. After some tests, it seems like they define a zone at the segment level of the path, like so: image segment zone. Another approach is to work with polygons. While giving better results, it still registers some unexpected touches, and misses obvious ones. But there is another solution, which consists in retrieving a set of points along the path, and registering touches inside an area surrounding them. For that, we can use PathMeasure
class to get the desired number of points, and store them in a List<Float>
:
PathMeasure pathMeasure = new PathMeasure(path, false);
List<Float> listFloat = new ArrayList<>();
for (float i = 0; i < 1.1; i += 0.1) {
float[] pointCoordinates = new float[2];
pathMeasure.getPosTan(pathMeasure.getLength() * i, pointCoordinates, null);
listFloat.add(pointCoordinates[0]);
listFloat.add(pointCoordinates[1]);
}
Then, we need to loop over the List<Float>
and check if a touch event is inside a defined zone surrounding these points. Here, a zone covers a tenth of the path length, since we collected ten points:
float areaLength = pathMeasure.getLength() / 20; // since we collect ten points, we define a zone covering a tenth of path length
for (int i = 0; i < listFloat.size() - 1; i += 2) {
if (touchX > listFloat.get(i) - areaLength
&& touchX < listFloat.get(i) + areaLength
&& touchY > listFloat.get(i+1) - areaLength
&& touchY < listFloat.get(i+1) + areaLength) {
Log.d(TAG, "path touched");
}
}
These successive zones capture touch events with a better precision, following more closely the path: image points zone.
This method can be improved, by working with Rect
class to ensure that these zones are not overlapping each other, and also to bound the start and end point with a better precision.