Home » Android » Android 2.2 Click and Drag Image Centered Under Touch

Android 2.2 Click and Drag Image Centered Under Touch

Posted by: admin June 15, 2020 Leave a comment


I am trying to drag and drop a crosshair onto a MapView. I have an ImageView button on the screen. When I touch it, the button disappears and a new ImageView appears. The new ImageView is supposed to sit centered under my finger until I release it somewhere, but for some reason the offset is incorrect. The crosshair appears down-right of where I am touching.

The image does move proportionately so I believe the problem is with the offset_x and offset_y which I define in the ACTION_DOWN section. Then, in ACTION_UP I need to createMarker(x,y) on the correct coordinates under my finger, but that is offset incorrectly as well.

I have tried various ways to make it centered, and some are better than others. I have so far been unable to make it work without using magic numbers.

As it is, I am using the click location and subtracting half the picture size. This makes sense to me. It’s closer to correct if I subtract the whole picture size. I have tried various examples from the web, all of them suffer from inaccuracies with the View location.

Can you give me some advice?

crosshair = (ImageView)findViewById(R.id.crosshair);
frameLayout = (FrameLayout)findViewById(R.id.mapframe);
params = new LayoutParams(LayoutParams.WRAP_CONTENT,
crosshairImage = BitmapFactory.decodeResource(getResources(), R.drawable.crosshair);
crosshair.setOnTouchListener(new OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            dragStatus = START_DRAGGING;

            // hide the button and grab a mobile crosshair
            image = new ImageView(getBaseContext());

            // set the image offsets to center the crosshair under my touch
            offset_x = (int)event.getRawX() - (int)(crosshairImage.getWidth()/2)  ;
            offset_y = (int)event.getRawY() - (int)(crosshairImage.getHeight()/2) ;

            // set the image location on the screen using padding
            image.setPadding(offset_x, offset_y, 0, 0);

            // add it to the screen so it shows up
            frameLayout.addView(image, params);

            if(LOG_V) Log.v(TAG, "Pressed Crosshair");
            return true;
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            if(dragStatus == START_DRAGGING) {
                dragStatus = STOP_DRAGGING;

                // place a marker on this spot
                makeMarker((int)event.getX() + offset_x, (int)event.getY() + offset_y); 

                // make the button visible again

                // remove the mobile crosshair

                if(LOG_V) Log.v(TAG, "Dropped Crosshair");
                return true;
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (dragStatus == START_DRAGGING) {
                // compute how far it has moved from 'start' offset
                int x =  (int)event.getX() + offset_x;
                int y = (int)event.getY() + offset_y; 

                // check that it's in bounds
                int w = getWindowManager().getDefaultDisplay().getWidth();
                int h = getWindowManager().getDefaultDisplay().getHeight();
                if(x > w)
                    x = w;
                if(y > h)
                    y = h;

                // set the padding to change the image loc
                image.setPadding(x, y, 0 , 0);

                // draw it

                if(LOG_V) Log.v(TAG, "(" + offset_x + ", " + offset_y + ")");

                return true;
        return false;

How to&Answers:

You have written this code within touch_Down.

offset_x = (int)event.getRawX() - (int)(crosshairImage.getWidth()/2)  ;
offset_y = (int)event.getRawY() - (int)(crosshairImage.getHeight()/2) ;

// set the image location on the screen using padding
image.setPadding(offset_x, offset_y, 0, 0);

Try writing it outside the if conditions, just to make sure, it is applied to all the touch events.


You can use new api available in drag and drop

public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(null, shadowBuilder, view, 0);
return true;
} else {
return false;