title: Dragging & Moving a bitmap about the screen
body: <p>I have tried implementing a method to drag&amp; drop a bitmap around on the screen. The method I tried worked when the card was an imageView and in the XML file, but I have changed my approach and I am just loading the bitmaps in to rects on the screen when the draw method is called. </p>
  
  <p>Can anyone advise me the best way to implement dragging and dropping for bitmaps that are loaded on to the screen? Thanks in advance.</p>
  
  <p>My Code:
  Play Screen Class:(Where bitmaps are loaded and drawn onto screen)</p>
  
  <pre><code>     package com.example.llave_000.shootout.screens;
  
  import android.content.Context;
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Matrix;
  import android.graphics.PointF;
  import android.graphics.Rect;
  import android.graphics.RectF;
  import android.view.MotionEvent;
  import android.view.ScaleGestureDetector;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.ImageView;
  import android.widget.RelativeLayout;
  import android.view.View.OnTouchListener;
  
  
  import com.example.llave_000.shootout.Game;
  import com.example.llave_000.shootout.MoveGestureDetector;
  import com.example.llave_000.shootout.R;
  import com.example.llave_000.shootout.Settings.Settings;
  import com.example.llave_000.shootout.engine.AssetStore;
  import com.example.llave_000.shootout.engine.ElapsedTime;
  import com.example.llave_000.shootout.engine.audio.Music;
  import com.example.llave_000.shootout.engine.graphics.IGraphics2D;
  import com.example.llave_000.shootout.engine.input.Input;
  import com.example.llave_000.shootout.engine.input.TouchEvent;
  
      import com.example.llave_000.shootout.world.GameObject;
      import com.example.llave_000.shootout.world.GameScreen;
      import com.example.llave_000.shootout.world.LayerViewport;
      import com.example.llave_000.shootout.world.ScreenViewport;
  
      import java.util.List;
  
      import static com.example.llave_000.shootout.R.id.imageView;
  
      public class PlayScreen extends GameScreen {
  
  
         // /////////////////////////////////////////////////////////////////////////
          // Properties
          // /////////////////////////////////////////////////////////////////////////
          private Rect backButtonBound;
          private Rect hazardCardBound;
  
          private Music screenClickMusic;
  
  
          /**
           * Width and height of the level
           */
         // private final float LEVEL_WIDTH = 1000.0f;
          //private final float LEVEL_HEIGHT = 1000.0f;
  
          /**
           * Define viewports for this layer and the associated screen projection
           */
          private ScreenViewport mScreenViewport;
          private LayerViewport mLayerViewport;
  
          private Bitmap backgroundBitmap;
          private Bitmap backButton;
          private Bitmap PlayScreenTitle;
          private Bitmap hazardCard;
          private Rect frontLayerBound;
          private Rect playScreenTitleBound;
  
          private ImageView cardImage1;
          private ViewGroup rootLayout;
          private int _xDelta;
          private int _yDelta;
          public View view;
  
          /**
           * User input controls for managing the player and the game
           */
         // protected InputControl pauseButton
  
          // /////////////////////////////////////////////////////////////////////////
          // Constructors
          // /////////////////////////////////////////////////////////////////////////
  
          /**
           * Create a game
           *
           * @param game
           *            Game to which this screen belongs */
  
          public PlayScreen(Game game) {
              super("PlayScreen", game);
  
              //Define the rects what will be used to 'hold' the images
              int spacingX = game.getScreenWidth() / 8;
              int spacingY = game.getScreenHeight() / 8;
              int padding = spacingY / 10;    //padding between each button
              int line = 1;   //each button is on a new 'line' (under each other)
  
  
              // Load in the assets used by the demo
              AssetStore assetManager = game.getAssetManager();
              assetManager.loadAndAddBitmap("pitch", "img/pitch.png");
              assetManager.loadAndAddBitmap("backButton", "img/back_button.png");
              assetManager.loadAndAddBitmap("hazardCard", "img/hazard_card.jpg");
  
  
              // Define Rectangles for Bitmaps
             // playScreenTitleBound = new Rect(spacingX * 2, spacingY * 0, spacingX * 6, spacingY * 1);
  
              this.backgroundBitmap = assetManager.getBitmap("pitch");
              this.backButton = assetManager.getBitmap("backButton");
              this.hazardCard = assetManager.getBitmap("hazardCard");
  
              //load in sounds
              assetManager.loadAndAddMusic("screenClickMusic", "music/buttonPress.mp3");
  
              //initialise
              this.screenClickMusic = assetManager.getMusic("screenClickMusic");
  
          }
  
          // /////////////////////////////////////////////////////////////////////////
          // Support methods
          // /////////////////////////////////////////////////////////////////////////
  
          // /////////////////////////////////////////////////////////////////////////
          // Update and Draw methods
          // /////////////////////////////////////////////////////////////////////////
  
          @Override
          public void update(ElapsedTime elapsedTime) {
  
              //process any touch events occurring since the update
              Input input = game.getInput();
              List&lt;TouchEvent&gt; touchEvents = input.getTouchEvents();
  
              if (touchEvents.size() &gt; 0) {
  
                  //Just check the first touch event that occurred in the frame.
                  //It means pressing the screen with several fingers may not
                  //trigger a 'button'.
                  TouchEvent touchEvent = touchEvents.get(0);
                  if (backButtonBound.contains((int) touchEvent.x, (int) touchEvent.y)
                          &amp;&amp; touchEvent.type == TouchEvent.TOUCH_UP) {
                      // If the play game area has been touched then swap screens
                      game.getScreenManager().removeScreen(this.getName());
                      MenuScreen menuScreen = new MenuScreen(game);
                      if (Settings.soundEnabled) {
                          screenClickMusic.play();
                      }
                      // As it's the only added screen it will become active.
                      game.getScreenManager().addScreen(menuScreen);
                  }
                  /*else if (hazardCardBound.contains((int) touchEvent.x, (int) touchEvent.y)
                          &amp;&amp; touchEvent.type == TouchEvent.TOUCH_DOWN) {
                      RelativeLayout.LayoutParams lparams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                      _xDelta = X - lparams.leftMargin;
                      _yDelta = Y - lparams.topMargin;
  
                  }*/
              }
          }
          @Override
          public void draw(ElapsedTime elapsedTime, IGraphics2D graphics2D) {
          //  load hazard playing card
              /*ImageView hazardCardImageView = (ImageView) view.findViewById(R.id.hazardCardImageView);
              if (hazardCard != null) {
                  hazardCardImageView.setImageBitmap(hazardCard);
              }
  
              cardImage1 = (ImageView) rootLayout.findViewById(R.id.hazardCardImageView);
              RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(500, 150);
              cardImage1.setLayoutParams(layoutParams);
              cardImage1.setOnTouchListener(new ChoiceTouchListener());*/
  
              // Get and draw the bitmaps into the defined rectangles
              Bitmap backButton = game.getAssetManager().getBitmap("backButton");
  
              // Create the screen to black and define a clip based on the viewport
              graphics2D.clear(Color.BLACK);
              //graphics2D.clipRect(mScreenViewport.toRect());
              // Define the rects what will be used to 'hold' the images
              int spacingX = game.getScreenWidth() / 8;
              int spacingY = game.getScreenHeight() / 8;
              int padding = spacingY / 10;    //padding between each button
              int line = 1;   //each button is on a new 'line' (under each other)
  
              hazardCardBound = new Rect(spacingX, spacingY * 2 + padding, spacingX * 7, spacingY * 3);
  
              if (frontLayerBound == null) {
                  frontLayerBound = new Rect(0, 0, graphics2D.getSurfaceWidth(),
                          graphics2D.getSurfaceHeight());
              }
  
              if (backButtonBound == null) {
                  int left = 10;
                  int bottom = (graphics2D.getSurfaceHeight() - 120);
  
                  backButtonBound = new Rect(left, bottom, left + 100, bottom + 120);
              }
  
              //cardImage1 = (ImageView)view.findViewById(R.id.hazardCardImageView);
       /*       RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(500, 150);
              cardImage1.setLayoutParams(layoutParams);
              cardImage1.setOnTouchListener(new ChoiceTouchListener());
              cardImage1.setOnTouchListener(new ChoiceTouchListener());
              cardImage1.setImageBitmap(hazardCard);*/
  
        //       RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(500, 150);
  
              //draw bitmaps with relative bounds
              graphics2D.drawBitmap(backgroundBitmap, null, frontLayerBound,null);
              graphics2D.drawBitmap(backButton, null, backButtonBound, null);
              graphics2D.drawBitmap(hazardCard,null, hazardCardBound, null);
  
  
  
             // RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(500, 150);
      //        cardImage1.setLayoutParams(layoutParams);
      //        cardImage1.setImageBitmap(hazardCard);
              //cardImage1.setOnTouchListener(new ChoiceTouchListener());
  
          }
  
  
        /*  @Override
          public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                   Bundle savedInstanceState) {
  
              // Inflate the layout for this fragment
              View view = inflater.inflate(R.layout.fragment_play_screen, container, false);
  
              FragmentManager fm = getFragmentManager();
              Fragment fragment = fm.findFragmentById(R.id.fragment_play_screen);
  
              if (fragment == null) {
      //            Log.d("","@ PLAY SCREEN"); --logcat shows execution reaches this point
                  fragment = createFragment();
                  fm.beginTransaction().add(R.id.fragment_play_screen, fragment)
                          .commit();
              }
  
              AssetManager assetManager = getActivity().getAssets();
  
              Bitmap backButton = loadBitmap(assetManager, "img/back_button.png");
  
              ImageView backButtonimageView = (ImageView) view.findViewById(R.id.backButton);
              if (backButton != null) {
                  backButtonimageView.setImageBitmap(backButton);
              }
              backButtonimageView.setOnClickListener(new View.OnClickListener() {
                  public void onClick(View v) {
                      Log.d("BACK BUTTON CLICKED", "BACK BUTTON CLICKED");
  
                      FragmentTransaction transaction = getFragmentManager().beginTransaction();
  
                      //go back to main menu screen
                      transaction.replace(R.id.fragment_play_screen, new MenuScreen());
                      transaction.addToBackStack(null);
  
                      // Commit the transaction
                      transaction.commit();
                  }
              });
  
  
  
          private Layer target;
  
      }
  
      class Layer {
          Matrix matrix = new Matrix();
          Matrix inverse = new Matrix();
          RectF bounds;
          View parent;
          Bitmap bitmap;
          MoveGestureDetector mgd;
  
          public Layer(Context ctx, View p, Bitmap b) {
              parent = p;
              bitmap = b;
              bounds = new RectF(0, 0, b.getWidth(), b.getHeight());
              mgd = new MoveGestureDetector(ctx, mgl);
              matrix.postTranslate(50 + (float) Math.random() * 50, 50 + (float) Math.random() * 50);
          }
  
          public boolean contains(MotionEvent event) {
              matrix.invert(inverse);
              float[] pts = {event.getX(), event.getY()};
              inverse.mapPoints(pts);
              if (!bounds.contains(pts[0], pts[1])) {
                  return false;
              }
              return Color.alpha(bitmap.getPixel((int) pts[0], (int) pts[1])) != 0;
          }
  
          public boolean onTouchEvent(MotionEvent event) {
              mgd.onTouchEvent(event);
              return true;
          }
  
          public void draw(Canvas canvas) {
              canvas.drawBitmap(bitmap, matrix, null);
          }
  
          MoveGestureDetector.SimpleOnMoveGestureListener mgl = new MoveGestureDetector.SimpleOnMoveGestureListener() {
              @Override
              public boolean onMove(MoveGestureDetector detector) {
                  PointF delta = detector.getFocusDelta();
                  matrix.postTranslate(delta.x, delta.y);
                  parent.invalidate();
                  return true;
              }
          };
  
  
  
  
      }
  </code></pre>
  
  <p>IGraphics2D Class:</p>
  
  <pre><code>/**
   * The graphics 2D interface defines the set of graphical operations that can be
   * applied to a render surface.
   * 
   * @version 1.0
   */
  public interface IGraphics2D {
  
      /**
       * Get the width of the render surface
       * 
       * @return Width of the render surface
       */
      public int getSurfaceWidth();
  
      /**
       * Get the height of the render surface
       * 
       * @return Height of the render surface
       */
      public int getSurfaceHeight();
  
      /**
       * Insert the specified rectangular clip region
       * 
       * @param clipRegion
       */
      public void clipRect(Rect clipRegion);
  
      /**
       * Set the surface colour to that specified colour (assumed to be in the
       * same format as the Color class - ARGB).
       * 
       * @param colour
       *            ARGB formatted colour
       */
      public void clear(int colour);
  
      /**
       * Draw the specified text string
       * 
       * @param text
       *            String of text to be rendered
       * @param x
       *            Location of text on x-axis
       * @param y
       *            Location of text on y-axis
       * @param paint
       *            Paint parameters controlling text render format
       */
      public void drawText(String text, float x, float y, Paint paint);
  
      /**
       * Draw the specified bitmap
       * 
       * @param bitmap
       *            Bitmap to be rendered
       * @param srcRect
       *            Source region to be rendered (if null full source is rendered)
       * @param desRect
       *            Destination region for the render
       * @param paint
       *            Paint parameters controlling how the bitmap is rendered
       */
      public void drawBitmap(Bitmap bitmap, Rect srcRect, Rect desRect,
                             Paint paint);
  
      /**
       * Draw the specified bitmap
       * 
       * @param bitmap
       *            Bitmap to be rendered
       * @param matrix
       *            Matrix defining bitmap scaling, rotation, translation, etc.
       * @param paint
       *            Paint parameters controlling how the bitmap is rendered
       */
      public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint);
  }
  </code></pre>
  
  <p>Edit:
  The method that worked was using this:</p>
  
  <pre><code>RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(500, 150);
          cardImage.setLayoutParams(layoutParams);
          cardImage.setOnTouchListener(new ChoiceTouchListener());
  
  
  
   //load hazard playing card
      Bitmap hazardCard = loadBitmap(assetManager, "img/hazard_card.jpg");
      ImageView hazardCardimageView = (ImageView) view.findViewById(R.id.hazardCardImageView);
      if (hazardCard != null) {
          hazardCardimageView.setImageBitmap(hazardCard);
      }
       private final class ChoiceTouchListener implements View.OnTouchListener {
              public boolean onTouch(View view, MotionEvent event) {
                  final int X = (int) event.getRawX();
                  final int Y = (int) event.getRawY();
                  switch (event.getAction() &amp; MotionEvent.ACTION_MASK) {
                      case MotionEvent.ACTION_DOWN:
                          RelativeLayout.LayoutParams lparams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                          _xDelta = X - lparams.leftMargin;
                          _yDelta = Y - lparams.topMargin;
                          break;
                      case MotionEvent.ACTION_UP:
                          break;
                      case MotionEvent.ACTION_POINTER_DOWN:
                          break;
                      case MotionEvent.ACTION_POINTER_UP:
                          break;
                      case MotionEvent.ACTION_MOVE:
                          RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
                          layoutParams.leftMargin = X - _xDelta;
                          layoutParams.topMargin = Y - _yDelta;
                          layoutParams.rightMargin = 0b11111111111111111111111100000110;
                          layoutParams.bottomMargin = 0b11111111111111111111111100000110;
                          view.setLayoutParams(layoutParams);
                          break;
                  }
                  rootLayout.invalidate();
                  return true;
              }
          }
  </code></pre>
  
  <p>Main Activity class:
  package com.example.llave_000.shootout;</p>
  
  <pre><code>import android.app.Activity;
  import android.app.FragmentManager;
  import android.graphics.PointF;
  import android.os.Bundle;
  import android.view.MotionEvent;
  import android.view.ScaleGestureDetector;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.Window;
  import android.view.WindowManager;
  
  import com.example.llave_000.shootout.world.DemoGame;
  import com.example.llave_000.shootout.BaseGestureDetector;
  import com.example.llave_000.shootout.MoveGestureDetector;
  import android.widget.ImageView;
  
  public class MainActivity extends Activity implements View.OnTouchListener {
  
      private float mScaleFactor = 1.0f;
      private float mRotationDegrees = 0.f;
      private float mFocusX = 0.f;
      private float mFocusY = 0.f;
  
      private ImageView cardImage1;
      private ViewGroup rootLayout;
      public View view;
  
      private MoveGestureDetector mMoveDetector;
  
  
      private ScaleGestureDetector mScaleDetector;
  /*    private RotationGestureDetector mRotateDetector;
      private MoveGestureDetector mMoveDetector;*/
  
      /**
       * Game fragment instance
       */
      private Game mGame;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
  
          super.onCreate(savedInstanceState);
  
          //ImageView hazardCardImageView = (ImageView) view.findViewById(R.id.hazardCardImageView);
  
          cardImage1 = (ImageView)findViewById(R.id.hazardCardImageView);
  
          // Setup Gesture Detectors
          mMoveDetector = new MoveGestureDetector(getApplicationContext(), new MoveListener());
          //mScaleDetector = new ScaleGestureDetector(getApplicationContext(), new ScaleListener());
          /*mRotateDetector = new RotationGestureDetector(getApplicationContext(), new RotateListener());
          mMoveDetector = new MoveGestureDetector(getApplicationContext(), new MoveListener());*/
  
  
          // Setup the window as suitable for a game, namely: full screen
          // with no title and a request to keep the screen on. The changes
          // are made before any content is inflated.
          Window window = getWindow();
          window.requestFeature(Window.FEATURE_NO_TITLE);
          window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
          window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  
          // Set the content view to use a simple frame layout
          setContentView(R.layout.activity_main);
  
          // Add in the main game fragment..
          FragmentManager fm = getFragmentManager();
         // MenuScreen menuScreen = (MenuScreen)fm.findFragmentById(R.id.activity_main_id);
          mGame = (Game)fm.findFragmentById(R.id.activity_main_id);
  
          if (mGame == null) {
              mGame = new DemoGame(); //not sure if correct
              fm.beginTransaction().add(R.id.activity_main_id, mGame)
                      .commit();
          }
  
          // Add in the main game fragment
       /*   if (savedInstanceState == null) {
              getFragmentManager().beginTransaction()
                      .add(R.id.activity_main_id, new MenuScreen()).commit();
          }*/
  
      }
  
      public boolean onTouch(View view, MotionEvent event) {
          mScaleDetector.onTouchEvent(event);
          mMoveDetector.onTouchEvent(event);
  
         /* mRotateDetector.onTouchEvent(event);
          mMoveDetector.onTouchEvent(event);
  */
          // Mmmmmhhhagic!!!
          //  with: mScaleFactor, mRotationDegrees, mFocusX and mFocusY
  
          return true; // indicate event was handled
      }
      private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
          @Override
          public boolean onScale(ScaleGestureDetector detector) {
              mScaleFactor *= detector.getScaleFactor(); // scale change since previous event
              return true;
          }
      }
  
   /*   private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
          @Override
          public boolean onRotate(RotateGestureDetector detector) {
              mRotationDegrees -= detector.getRotationDegreesDelta();
              return true;
          }
      }
  */
      private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
          @Override
          public boolean onMove(MoveGestureDetector detector) {
              PointF d = detector.getFocusDelta();
              mFocusX += d.x;
              mFocusY += d.y;
  
              return true;
          }
      }
  
  
  
      @Override
      public void onBackPressed() {
          // If the fragment does not consume the back event then
          // trigger the default behaviour
          if(!mGame.onBackPressed())
              super.onBackPressed();
      }
  
     /* public boolean onTouchEvent(MotionEvent me) {
          if (me.getAction() == MotionEvent.ACTION_DOWN) {
              //code in here to take me to new screen with match attax background
              //with new screen displaying a card. then work on being able to move that card.
  
              //playButtonY -= 20;
  
          }*/
         // playButton.setY(playButtonY);
          //code in here to take me to new screen with match attax background
          //with new screen displaying a card. then work on being able to move that card.
  
          //return true;
      }
  </code></pre>
  
  <p>..</p>