Pixplicity / sharp

Scalable vector graphics for Android
Apache License 2.0
1.03k stars 117 forks source link

set click event for each path #29

Open tracyallen opened 8 years ago

tracyallen commented 8 years ago

if there are many path in xxx.svg file, how can i set click event for each path ?

abdallaadelessa commented 8 years ago

public class ImageMapTestActivity extends Activity { private ImageView mImageMap; private Sharp mSvg; private Toast toast; private RectF canvasBounds; private PhotoViewAttacher mAttacher; Set regions = new HashSet(); private String selectedId;

// --------------->

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    toast = Toast.makeText(ImageMapTestActivity.this, "", Toast.LENGTH_SHORT);
    mImageMap = (ImageView) findViewById(R.id.map);
    mAttacher = new PhotoViewAttacher(mImageMap);
    mAttacher.setMaximumScale(10f);
    mAttacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
        @Override
        public void onPhotoTap(View view, float x, float y) {
            boolean canHandleClick = false;
            PointF sCoord = toImageBound(x, y);
            for(Region region : regions) {
                RectF rectF = new RectF();
                region.path.computeBounds(rectF, true);
                if(region.elementBounds.contains(sCoord.x, sCoord.y)) {
                    canHandleClick = true;
                    selectedId = region.id;
                }
            }
            if(canHandleClick) refreshSvg();
        }
    });
    mSvg = Sharp.loadResource(getResources(), R.raw.cartman);
    refreshSvg();
}

// --------------->

private void refreshSvg() {
    mSvg.setOnElementListener(new OnSvgElementListener() {
        @Nullable
        @Override
        public void onSvgStart(@NonNull Canvas canvas, @Nullable RectF bounds) {
        }

        @Override
        public void onSvgEnd(@NonNull Canvas canvas, @Nullable RectF bounds) {
        }

        @Override
        public <T> T onSvgElement(@Nullable String id, @NonNull T element, @Nullable RectF elementBounds, @NonNull Canvas canvas, @Nullable RectF canvasBounds, @Nullable Paint paint) {
            if(paint != null && paint.getStyle() == Paint.Style.FILL) {
                ImageMapTestActivity.this.canvasBounds = canvasBounds;
                regions.add(new Region(id, (Path) element, new RectF(elementBounds)));
                if(selectedId != null && selectedId.equals(id)) {
                    paint.setColor(Color.BLACK);
                }
            }
            return element;
        }

        @Override
        public <T> void onSvgElementDrawn(@Nullable String id, @NonNull T element, @NonNull Canvas canvas, @Nullable Paint paint) {
        }

    });
    mSvg.getSharpPicture(new Sharp.PictureCallback() {
        @Override
        public void onPictureReady(SharpPicture picture) {
            Drawable drawable = picture.getDrawable(mImageMap);
            mImageMap.setImageDrawable(drawable);
            //mAttacher.update();
        }
    });
}

// --------------->

@NonNull
private PointF toImageBound(float x, float y) {
    return new PointF(x * canvasBounds.right, y * canvasBounds.bottom);
}

public static class Region {
    public String id;
    public RectF elementBounds;
    public Path path;

    public Region(String id, Path path, RectF elementBounds) {
        this.id = id;
        this.path = path;
        this.elementBounds = elementBounds;
    }

    @Override
    public boolean equals(Object o) {
        if(this == o) return true;
        if(o == null || getClass() != o.getClass()) return false;

        Region region = (Region) o;

        return id != null ? id.equals(region.id) : region.id == null;

    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}

}

ajilo297 commented 6 years ago

@abdallaadelessa I have got to admit that without the block of code you provided, I would have been stuck at detecting click events on different paths for a long time. So thanks for that.

However I think that code inside the onPhotoTapListener can be improved slightly. Right now, the touch events are detected based on whether the touch falls within the bounds of the path. While this may work for most cases involving convex paths, it causes problems when the path bounds of different paths overlap. I have changed the code a little to overcome the problem

    PhotoViewAttacher attach = new PhotoViewAttacher(mapView);
    attach.setOnPhotoTapListener(new OnPhotoTapListener() {
        @Override
        public void onPhotoTap(ImageView view, float x, float y) {
            boolean canHandleClick = false;

            PointF cPoint = toImageBound(x, y);

            for (Region region : regions) {
                Path rPath = region.path;
                Path tapPath = new Path();
                tapPath.addRect(cPoint.x - 0.25f, cPoint.y - 0.25f, cPoint.x + 0.25f, cPoint.y + 0.25f, Path.Direction.CW);

                Path path = new Path();
                boolean intersects = path.op(tapPath, rPath, Path.Op.INTERSECT);

                if (intersects && !path.isEmpty()) {
                    canHandleClick = true;
                    selectedId = region.id;
                    break;
                }
            }
            if(canHandleClick) refreshSVG();
        }
    });

I am not sure if this is memory efficient, but it does the job for me and I hope it helps someone out there.

asadaltaf583 commented 8 months ago

can you guys explain PhotoViewAttacher? is it library?