Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subsampling scale image view - make pin markers clickable on Imageview

I'm using Dave Morrissey's Subsampling Scale Image View. I modified the 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) to support array of pin's. Now I want to make each pin clickable to set off an on click function. Below code places multiple markers correctly. Please let me know how to make each pin's clickable and I want to read the id inside click event function and display in a toast example MapPin(1718f, 581f, (id) 1).

Modified PinView.java

   public class PinView extends SubsamplingScaleImageView {

   private PointF sPin;

   ArrayList<MapPin> mapPins;
   ArrayList<DrawPin> drawnPins;
   Context context;
   String tag = getClass().getSimpleName();

   public PinView(Context context) {
    this(context, null);
    this.context = context;
   }

   public PinView(Context context, AttributeSet attr) {
    super(context, attr);
    this.context = context;
    initialise();
   }

   public void setPins(ArrayList<MapPin> mapPins) {
    this.mapPins = mapPins;
    initialise();
    invalidate();
   }

   public void setPin(PointF pin) {
    this.sPin = pin;
   }

   public PointF getPin() {
    return sPin;
   }

   private void initialise() {

   }

   @Override
   protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // Don't draw pin before image is ready so it doesn't move around during       setup.
    if (!isReady()) {
        return;
    }

    drawnPins = new ArrayList<>();

    Paint paint = new Paint();
    paint.setAntiAlias(true);
    float density = getResources().getDisplayMetrics().densityDpi;


    for (int i = 0; i < mapPins.size(); i++) {
        MapPin mPin = mapPins.get(i);
        //Bitmap bmpPin = Utils.getBitmapFromAsset(context, mPin.getPinImgSrc());
        Bitmap bmpPin = BitmapFactory.decodeResource(this.getResources(), drawable.pushpin_blue);

        float w = (density / 420f) * bmpPin.getWidth();
        float h = (density / 420f) * bmpPin.getHeight();
        bmpPin = Bitmap.createScaledBitmap(bmpPin, (int) w, (int) h, true);

        PointF vPin = sourceToViewCoord(mPin.getPoint());
        //in my case value of point are at center point of pin image, so we need to adjust it here

        float vX = vPin.x - (bmpPin.getWidth() / 2);
        float vY = vPin.y - bmpPin.getHeight();


        canvas.drawBitmap(bmpPin, vX, vY, paint);

        //add added pin to an Array list to get touched pin
        DrawPin dPin = new DrawPin();
        dPin.setStartX(mPin.getX() - w / 2);
        dPin.setEndX(mPin.getX() + w / 2);
        dPin.setStartY(mPin.getY() - h / 2);
        dPin.setEndY(mPin.getY() + h / 2);
        dPin.setId(mPin.getId());
        drawnPins.add(dPin);
    }
}

public int getPinIdByPoint(PointF point) {

    for (int i = drawnPins.size() - 1; i >= 0; i--) {
        DrawPin dPin = drawnPins.get(i);
        if (point.x >= dPin.getStartX() && point.x <= dPin.getEndX()) {
            if (point.y >= dPin.getStartY() && point.y <= dPin.getEndY()) {
                return dPin.getId();
            }
        }
    }
    return -1; //negative no means no pin selected
}
}

MapPin.java

    public class MapPin {
    float X, Y;
    int id;

        public MapPin(float X, float Y, int id) {
            this.X = X;
            this.Y = Y;
            this.id = id;
        }

        public MapPin() {
        }

        public float getX() {
            return X;
        }

        public void setX(float X) {
            this.X = X;
        }

        public float getY() {
            return Y;
        }

        public void setY(float Y) {
            this.Y = Y;
        }

        public PointF getPoint() {
            return new PointF(this.X, this.Y);
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }
    }

DrawPin.java

public class DrawPin {

    float startX, startY, endX, endY;
    int id;

    public DrawPin(float startX, float startY, float endX, float endY, int id) {
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
        this.id = id;
    }

    public DrawPin() {
        //empty
    }

    public float getStartX() {
        return startX;
    }

    public void setStartX(float startX) {
        this.startX = startX;
    }

    public float getStartY() {
        return startY;
    }

    public void setStartY(float startY) {
        this.startY = startY;
    }

    public float getEndX() {
        return endX;
    }

    public void setEndX(float endX) {
        this.endX = endX;
    }

    public float getEndY() {
        return endY;
    }

    public void setEndY(float endY) {
        this.endY = endY;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

ExtensionPinFragment

public class ExtensionPinFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(layout.extension_pin_fragment, container, false);
        rootView.findViewById(id.next).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                ((ExtensionActivity) getActivity()).next();
            }
        });
        PinView imageView = (PinView)rootView.findViewById(id.imageView);
        imageView.setImage(ImageSource.asset("squirrel.jpg"));

        MapPin mapPin = new MapPin(1718f, 581f, 1);
        MapPin mapPin1 = new MapPin(500f, 681f, 2);

        ArrayList<MapPin> MapPins = new ArrayList();
        MapPins.add(new MapPin(1718f, 581f, 1));
        MapPins.add(new MapPin(500f, 681f, 2));
        imageView.setPins(MapPins);

        // Below on click listener associated with entire image but I want the click event listener for individual pins

        imageView.setOnClickListener(new OnClickListener() {
                                         @Override
                                         public void onClick(View view) {
                                             ((ExtensionActivity) getActivity()).next();
                                         }
                                     }
        );
        return rootView;
    }
}
like image 898
venkatesh shanmuganathan Avatar asked Oct 19 '22 15:10

venkatesh shanmuganathan


1 Answers

Currently working on the same issue: You could add a gestureDetector and a touch listener to your custom view as suggested in: https://github.com/davemorrissey/subsampling-scale-image-view/wiki/09.-Events

In the GestureDetector override the onSingleTapConfirmed() method and check if the tapped touch coordinate matches a pin coordinate (use sourceToView for transforming touch and pin coordinates...) and if so handle whatever code you want to be executed.

Here is part of the code in my custom SubsamplingScaleImageView which gets called after the pin have been added to the view:

  private void setTouchListener() {
    /** https://github.com/davemorrissey/subsampling-scale-image-view/wiki/09.-Events:
     *  ...you must check that the view is ready with the isReady() method before attempting to convert screen
     *  coordinates to image coordinates. A NullPointerException may be thrown if you don't. It is safe to override
     *  onSingleTapUp, onSingleTapConfirmed, onLongPress and onDown from the SimpleOnGestureListener class. If you
     *  override other methods, you will prevent the view from properly handling double taps, zoom and pan gestures.
     */

    final GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            if (isReady() && deeplinkCoordinates != null) {
                PointF tappedCoordinate = new PointF(e.getX(), e.getY());

                int blockWidth = deepLinkBitmap.getWidth();
                int blockHeight = deepLinkBitmap.getHeight();

                // check if deepLinkBitmap is touched
                for (PointF deeplink : deeplinkCoordinates) {
                    PointF deeplinkCoordinate = sourceToViewCoord(deeplink);
                    int deeplinkX = (int) (deeplinkCoordinate.x - (deepLinkBitmap.getWidth() / 2));
                    int deeplinkY = (int) (deeplinkCoordinate.y - deepLinkBitmap.getHeight());

                    // center coordinate -/+ blockWidth actually sets touchable area to 2x icon size
                    if (tappedCoordinate.x >= deeplinkX - blockWidth && tappedCoordinate.x <= deeplinkX + blockWidth &&
                            tappedCoordinate.y >= deeplinkY - blockHeight && tappedCoordinate.y <= deeplinkY + blockHeight) {
                        // App.toast("You tapped on a deeplink!");
                    } 
                }
            }
            return true;
        }
    });

    setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            return gestureDetector.onTouchEvent(motionEvent);
        }
    });
}
like image 94
Rik van Velzen Avatar answered Nov 04 '22 02:11

Rik van Velzen