Search code examples
androiddrag-and-droptouchdrag

Dragging an imageview to certain position


I am trying to create a draggable imageView ("chatHead" in the code, kinda like the chat head of Facebook)

I followed the instruction on the android website but whereever I drag the imageview, it always ends up at the left upper corner. (with x,y cordinate being (0,0) ~ (90,90))

Later on I found out the problem is that the case: MotionEvent.ACTION_MOVE is only entered when my touch is around the imageView location.

And when I drag a bit further away from the imageView, ACTION_MOVE is no longer entered. And instead the case DragEvent.ACTION_DRAG_EXIT is executed.

Can someone tell me how can I expand the area for the ACTION_MOVE to be executed or what is the problem. I would like to locate the imageView at whichever location I want on the screen.
( you may just focus on onDragListener, the MyDragShadowBuilder is a customized extending DragShawdowBuilder and onLongClickListener is just to trigger the drag)

How to keep the imageView even the app is closed?

public class ChatHead extends Service {

private WindowManager windowManager;
private ImageView chatHead;
private WindowManager.LayoutParams params;
private final String CHAT_TAG ="CHAT";
private int cor_x = 0;
private int cor_y = 0;



@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override public void onCreate() {
    super.onCreate();
    ImageView image = new ImageView(this);
    Log.d("", "created");
    windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

    chatHead = new ImageView(this);
    chatHead.setTag(CHAT_TAG);
    chatHead.setImageResource(R.drawable.chat_icon);

     params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.TOP | Gravity.LEFT;
    params.x = 300;
    params.y = 300;



    chatHead.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {



                    ClipData.Item item = new ClipData.Item(v.getTag().toString());


                    String[] mimeTypes =  {ClipDescription.MIMETYPE_TEXT_PLAIN};
                    ClipData dragData = new ClipData(v.getTag().toString(), mimeTypes,item);

                    View.DragShadowBuilder myShadow = new MyDragShadowBuilder(chatHead);

                    // Starts the drag

                    v.startDrag(dragData,  // the data to be dragged
                            myShadow,      // the drag shadow builder
                            null,          // no need to use local data
                            0              // flags (not currently used, set to 0)
                    );

            return false;}

    });



    chatHead.setOnDragListener(new View.OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {

            //cor_x = ((int) chatHead.getX());
            //cor_y = ((int) chatHead.getY());

            switch (event.getAction()){
                case DragEvent.ACTION_DRAG_ENTERED : { Log.d("", "x:"+ event.getX()+"y:"+event.getY());break;}
                case DragEvent.ACTION_DRAG_STARTED : { Log.d("", "x:"+ event.getX()+"  y:"+event.getY());break;}

                case MotionEvent.ACTION_MOVE:  {
                    cor_x = ((int) event.getX());
                    cor_y = ((int) event.getX());
                    Log.d("", "x:"+ cor_x+"  y:"+cor_y);
                    break;}
                case DragEvent.ACTION_DRAG_EXITED:{
                    Log.d("", "x:"+ cor_x+"  y:"+cor_y);
                    break;
                }


                case DragEvent.ACTION_DRAG_ENDED   :  {
                    if(windowManager!=null && params!=null){
                        params.x = cor_x;
                        params.y = cor_y;
                        Log.d("", "x:"+ cor_x+"  y:"+cor_y);
                        windowManager.removeView(chatHead);
                        windowManager.addView(chatHead, params);
                    }

                    return false;
                }

            }


            return false;
        }
    });

    windowManager.addView(chatHead, params);


}

Solution

  • If I understand what you mean, your problem is that you don't get the MotionEvent.ACTION_MOVE unless your finger is above your image.

    Well that is because the concept of DragListener is that the View that register that listener, accept the events. So the only view in your layout that register to those events is chatHead, and he gets only the events that occur above him.

    So if you want to get all the events in layout you must register view that take the whole screen space. So the quickest solution is to wrap the view with container that take the whole screen, and register it instead the chatHead to the DragListener. Somethong like:

      windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        RelativeLayout container = new RelativeLayout(this);
    
    
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
    
        chatHead = new ImageView(this);
        chatHead.setTag(CHAT_TAG);
        chatHead.setImageResource(R.drawable.chat_icon);
    
        RelativeLayout.LayoutParams chatHeadParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        chatHeadParams.addRule(Gravity.TOP | Gravity.LEFT)  ;
        chatHeadParams.leftMargin = 300;
        chatHeadParams.topMargin = 300;
    
        container.addView(chatHead, chatHeadParams);
        windowManager.addView(container, params);
    

    And changing the line:

        chatHead.setOnLongClickListener(new View.OnLongClickListener() {
    

    to:

        container.setOnLongClickListener(new View.OnLongClickListener() {
    

    You may also adjust additional things because the DragEvent event.getX() and event.getX() will return different values according to the View itself and the DragEvent.Action type.