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

Questions:

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,
        LayoutParams.WRAP_CONTENT);
crosshairImage = BitmapFactory.decodeResource(getResources(), R.drawable.crosshair);
crosshair.setOnTouchListener(new OnTouchListener() {

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

            // hide the button and grab a mobile crosshair
            v.setVisibility(View.INVISIBLE);
            image = new ImageView(getBaseContext());
            image.setImageBitmap(crosshairImage);

            // 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);
            frameLayout.invalidate();

            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
                v.setVisibility(View.VISIBLE);

                // remove the mobile crosshair
                frameLayout.removeView(image);

                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
                image.invalidate();
                frameLayout.requestLayout();

                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.

Answer:

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);
view.setVisibility(View.INVISIBLE);
return true;
} else {
return false;
}
}