Thursday, January 20, 2011

Drag/Move a image in a custom view - part I

This post could be a first step of approach in moving a image in a view. With this approach you can start creating (base view and image movements) for a simple games like number puzzles, crosswords, pin ball.

1 - Create a class extends view. and override onDraw() and decide what are the contents you need to draw.

2 -To Keep moving a image in a view, we should be keep changing the x,y position of the image. This is the basic for image movement in a view

3 - In this example, a rectangle is drawn. And its position is hold in a variable ' Rect ImagePosition'

4 - When movement is detected 'ACTION_MOVE' event in 'OnTouchEvent()' function, deltaX is calcualted with the previous (x,y) and current moved (x,y) and a check is made like, whether , if the deltas are added to mImagePosition (top, left and bottom right ) is withing the visible screen. If 'yes', then deltax are added to 'Rect mImagePosition'. And invalidate() is called to draw() method to draw the rectangle. So it looks like the object is moving as when touched and moved along with the finger.


mImagePosition.left = mImagePosition.left + deltaX;
mImagePosition.top = mImagePosition.top + deltaY;
mImagePosition.right = mImagePosition.left + mImageWidth;
mImagePosition.bottom = mImagePosition.top + mImageHeight;
mImageRegion.set(mImagePosition);
prevX = positionX;
prevY = positionY;

invalidate();


Here is the complete code, i have tried out.

dragimage.java
----------------


import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

public class dragimage extends Activity {

sample mView;
sample1 mView1;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}
}


main.xml:
----------


android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:id="@+id/view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>




sample.java:
-------------


package com.mani.dragimage;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
public final class sample extends View{
Paint mPaint;
Rect mRect;
Bitmap bitmap;
private int mTouchSlop;
private int mTouchMode;
int mScreenHeight;
int mScreenWidth;
int prevX;
int prevY;
static final int TOUCH_MODE_TAP = 1;
static final int TOUCH_MODE_DOWN = 2;
final int mImageWidth = 100;
final int mImageHeight = 100;
Rect mImagePosition;
Region mImageRegion;
boolean canImageMove;

public sample(Context context,AttributeSet attrs)
{
super(context,attrs);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.chrome);
mPaint = new Paint();
mPaint.setTextSize(25);
mPaint.setColor(0xFF0000FF);
//Size for image
mImagePosition = new Rect(10,10,mImageWidth,mImageHeight);
mImageRegion = new Region();
mImageRegion.set(mImagePosition);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
Display display = (WindowManager)context.getSystemService(context.WINDOW_SERVICE)).getDefaultDisplay();
mScreenHeight = display.getHeight();
mScreenWidth = display.getWidth();
canImageMove = false;
}


public boolean onTouchEvent(MotionEvent event)
{
int positionX = (int)event.getRawX();
int positionY = (int)event.getRawY();

switch(event.getAction())
{
case MotionEvent.ACTION_DOWN: {
mTouchMode = TOUCH_MODE_DOWN;

if(mImageRegion.contains(positionX, positionY))
{
prevX = positionX;
prevY = positionY;
canImageMove = true;
}
}
break;

case MotionEvent.ACTION_MOVE:
{
if(canImageMove == true)
{
// Check if we have moved far enough that it looks more like a
// scroll than a tap
final int distY = Math.abs(positionY - prevY);
final int distX = Math.abs(positionX - prevX);

if (distX > mTouchSlop || distY > mTouchSlop)
{
int deltaX = positionX-prevX ;
int deltaY = positionY-prevY;
// Check if delta is added, is the rectangle is within the visible screen
if((mImagePosition.left+ deltaX) > 0 && ((mImagePosition.right +deltaX) < mScreenWidth ) && (mImagePosition.top +deltaY) >0 && ((mImagePosition.bottom+deltaY)))
{
// invalidate current position as we are moving...
mImagePosition.left = mImagePosition.left + deltaX;
mImagePosition.top = mImagePosition.top + deltaY;
mImagePosition.right = mImagePosition.left + mImageWidth;
mImagePosition.bottom = mImagePosition.top + mImageHeight;
mImageRegion.set(mImagePosition);
prevX = positionX;
prevY = positionY;

invalidate();
}
}
}
}
break;
case MotionEvent.ACTION_UP:
canImageMove = false;
break;
}
return true;
}

@Override
public void onDraw(Canvas canvas)
{
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);

// make the entire canvas white
paint.setColor(Color.CYAN);
Rect rect = new Rect(0,0,this.getWidth(),this.getHeight());
canvas.drawRect(mImagePosition, paint);
//canvas.drawBitmap(bitmap, null,mImagePosition, null);
}


}

10 comments:

  1. What is the difference in using this approach and using a Surfaceview?..atul

    ReplyDelete
  2. Just trying your code, eclipse tells me:
    "The operator && is undefined for the argument type(s) boolean, int"

    Let´s see, if Google can help me ;-)

    ReplyDelete
    Replies
    1. The correct one is:

      if((mImagePosition.left + deltaX > 0)
      && (mImagePosition.right + deltaX < mScreenWidth)
      && (mImagePosition.top + deltaY > 0)
      && (mImagePosition.bottom + deltaY < mScreenHeight))
      {
      // invalidate current position as we are moving...
      mImagePosition.left = mImagePosition.left + deltaX;
      mImagePosition.top = mImagePosition.top + deltaY;
      mImagePosition.right = mImagePosition.left + mImageWidth;
      mImagePosition.bottom = mImagePosition.top + mImageHeight;
      mImageRegion.set(mImagePosition);
      prevX = positionX;
      prevY = positionY;

      invalidate();
      }

      Delete
    2. Also missing a '(' before (WindowManager) at line 52.
      Correct: Display display = ((WindowManager)context.getSystemService(context.WINDOW_SERVICE)).getDefaultDisplay();

      Delete
  3. Hi
    can u tell me how to move text up and down from the list view, and the list view is from the database..

    ReplyDelete
  4. Suppose there are two (or more) fingers on the screen. One might have caused canImageMove to become true, but it might be a different finger which is moving.

    ReplyDelete
  5. if you have an image, how to drag them together? I mean you have 1 imageview and 1 rectangle how to drag them together? please help me...

    ReplyDelete
  6. where is invalidate() function ???????????

    ReplyDelete
  7. invalidate(); is present in onTouchEvent() method.

    ReplyDelete