Search code examples
androidbitmapuiimageviewimageviewsubsampling

How to make a pin markers clickable on Imageview


I'm using Dave Morrissey's Subsampling Scale Image View. I'm using his Pinview example (as shown here: https://github.com/davemorrissey/subsampling-scale-image-view/blob/master/sample/src/com/davemorrissey/labs/subscaleview/sample/extension/views/PinView.java)

What I've done differently is that I've created an ArrayList of Bitmaps that are Pins. But I want to make each pin clickable to set off an on click function. I know Bitmaps can not be clicked on. I have multiple pins on a map image and would like for each pin to be associated with an object.

What would be the best approach to accomplish this?

Note: I did override the setOnClickListener method inside of the Pinview class, but what happens that all pins that were dropped become associated to the same object. And that clearing 1 pin would then clear all pins.


Solution

  • The model that stores the bitmap, pointF and point name:

    public class CategoryPoint {
        private String category;
        private Bitmap image;
        private PointF pointF;
    
        public CategoryPoint(String category, Bitmap image, PointF pointF) {
            this.category = category;
            this.image = image;
            this.pointF = pointF;
        }
    
        // getters/setters
    }
    

    View looks like this:

    public class PinsView extends SubsamplingScaleImageView {
        private OnPinClickListener onPinClickListener;
        private final Paint paint = new Paint();
        private List<CategoryPoint> categoryPoints;
    
        public PinsView(Context context) {
            this(context, null);
        }
    
        public PinsView(Context context, AttributeSet attr) {
            super(context, attr);
            categoryPoints = new ArrayList<>();
            initTouchListener();
        }
    
        public void addCategories(List<CategoryPoint> categoryPoints) {
            this.categoryPoints = categoryPoints;
            invalidate();
        }
    
        public void removeCategories(List<CategoryPoint> categoryPoints) {
            this.categoryPoints.removeAll(categoryPoints);
            invalidate();
        }
    
        public void removeAllCategories() {
            this.categoryPoints.clear();
            invalidate();
        }
    
        public void setOnPinClickListener(OnPinClickListener listener) {
            onPinClickListener = listener;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (!isReady()) {
                return;
            }
            paint.setAntiAlias(true);
            for (CategoryPoint categoryPoint: categoryPoints) {
                Bitmap pinIcon = categoryPoint.getImage();
                if (categoryPoint.getPointF() != null && categoryPoint.getImage() != null) {
                    PointF point = sourceToViewCoord(categoryPoint.getPointF());
                    float vX = point.x - (pinIcon.getWidth()/2);
                    float vY = point.y - pinIcon.getHeight();
                    canvas.drawBitmap(pinIcon, vX, vY, paint);
                }
            }
        }
    
        private void initTouchListener() {
            GestureDetector gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onSingleTapConfirmed(MotionEvent e) {
                    if (isReady() && categoryPoints != null) {
                        PointF tappedCoordinate = new PointF(e.getX(), e.getY());
                        Bitmap clickArea = categoryPoints.get(0).getImage();
                        int clickAreaWidth = clickArea.getWidth();
                        int clickAreaHeight = clickArea.getHeight();
                        for (CategoryPoint categoryPoint : categoryPoints) {
                            PointF categoryCoordinate = sourceToViewCoord(categoryPoint.getPointF());
                            int categoryX = (int) (categoryCoordinate.x);
                            int categoryY = (int) (categoryCoordinate.y - clickAreaHeight / 2);
                            if (tappedCoordinate.x >= categoryX - clickAreaWidth / 2
                                && tappedCoordinate.x <= categoryX + clickAreaWidth / 2
                                && tappedCoordinate.y >= categoryY - clickAreaHeight / 2
                                && tappedCoordinate.y <= categoryY + clickAreaHeight / 2) {
                                onPinClickListener.onPinClick(categoryPoint);
                                break;
                            }
                        }
                    }
                    return true;
                }
            });
            setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event));
        }
    }
    

    Fragment:

    pinView.setOnImageEventListener(this);
    pinView.setOnPinClickListener(this);
    
    // implementation