Replacement for MapView's OnLongPressListener (from m5rc15)

Common bugs/problems with the Android SDK the Emulator and the ADT-Plugin.

Replacement for MapView's OnLongPressListener (from m5rc15)

Postby plusminus » Fri Sep 05, 2008 4:40 am

Hey guys,

so for everyone who is interested, this is my replacement-Class for MapView's OnLongPressListener, which is gone since Android SDK v0.9 :

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package org.anddev.andnav.apk.ui.common.views;
  2.  
  3.  
  4.  
  5. import android.view.MotionEvent;
  6.  
  7. import android.view.View;
  8.  
  9. import android.view.View.OnTouchListener;
  10.  
  11.  
  12.  
  13.  
  14.  
  15. public abstract class OnTouchAndLongPressListener implements OnTouchListener{
  16.  
  17.         // ===========================================================
  18.  
  19.         // Constants
  20.  
  21.         // ===========================================================
  22.  
  23.        
  24.  
  25.         /** Time in milliseconds until a TouchEvent should be registered as an actual LongPress. */
  26.  
  27.         public static final long LONGPRESS_DOWNTIME = 1200;
  28.  
  29.         public static final int LONGPRESS_MAXDIST_POW2 = 5*5;
  30.  
  31.  
  32.  
  33.         // ===========================================================
  34.  
  35.         // Fields
  36.  
  37.         // ===========================================================
  38.  
  39.        
  40.  
  41.         protected boolean mLongPressTriggeredThisMotion = false;
  42.  
  43.         protected final boolean mNoTouchEvents;
  44.  
  45.        
  46.  
  47.         protected int mDownX, mDownY;
  48.  
  49.  
  50.  
  51.         // ===========================================================
  52.  
  53.         // Constructors
  54.  
  55.         // ===========================================================
  56.  
  57.        
  58.  
  59.         public OnTouchAndLongPressListener(boolean noTouchEvents){
  60.  
  61.                 this.mNoTouchEvents = noTouchEvents;
  62.  
  63.         }
  64.  
  65.  
  66.  
  67.         // ===========================================================
  68.  
  69.         // Getter & Setter
  70.  
  71.         // ===========================================================
  72.  
  73.  
  74.  
  75.         // ===========================================================
  76.  
  77.         // Methods from SuperClass/Interfaces
  78.  
  79.         // ===========================================================
  80.  
  81.         @Override
  82.  
  83.         public final boolean onTouch(final View v, final MotionEvent moEv) {
  84.  
  85.                 final int action = moEv.getAction();
  86.  
  87.                 final int x = (int)moEv.getX();
  88.  
  89.                 final int y = (int)moEv.getY();
  90.  
  91.                 switch(action){
  92.  
  93.                         case MotionEvent.ACTION_CANCEL:
  94.  
  95.                                 mLongPressTriggeredThisMotion = false;
  96.  
  97.                                 break;
  98.  
  99.                         case MotionEvent.ACTION_MOVE:
  100.  
  101.                         case MotionEvent.ACTION_UP:
  102.  
  103.                                 final int dx = mDownX - x;
  104.  
  105.                                 final int dy = mDownY - y;
  106.  
  107.                                 final boolean movedFar = dx*dx + dy*dy > LONGPRESS_MAXDIST_POW2;
  108.  
  109.                                 if(!movedFar && !mLongPressTriggeredThisMotion && (moEv.getEventTime() - moEv.getDownTime() > LONGPRESS_DOWNTIME)){
  110.  
  111.                                         mLongPressTriggeredThisMotion = true;
  112.  
  113.                                         onLongPress(v, x, y);  
  114.  
  115.                                 }
  116.  
  117.                                 break;
  118.  
  119.                         case MotionEvent.ACTION_DOWN:
  120.  
  121.                                 mDownX = (int)x;
  122.  
  123.                                 mDownY = (int)y;                               
  124.  
  125.                                 mLongPressTriggeredThisMotion = false;
  126.  
  127.                                 break;
  128.  
  129.                 }
  130.  
  131.                 return onTouchEvent(v, moEv);
  132.  
  133.         }
  134.  
  135.  
  136.  
  137.         // ===========================================================
  138.  
  139.         // Methods
  140.  
  141.         // ===========================================================
  142.  
  143.        
  144.  
  145.         public abstract boolean onTouchEvent(View v, MotionEvent moEv);
  146.  
  147.  
  148.  
  149.         public abstract void onLongPress(final View v, final float x, final float y);
  150.  
  151.  
  152.  
  153.         // ===========================================================
  154.  
  155.         // Inner and Anonymous Classes
  156.  
  157.         // ===========================================================
  158.  
  159. }
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


What before was similar to this:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. this.mMapView.setOnLongPressListener(new OnLongPressListener() {
  2.  
  3.         @Override
  4.  
  5.         public boolean onLongPress(final View v, final float x, final float y) {
  6.  
  7.                 final MapView mapView = getMyMapView(); // Drag to local field
  8.  
  9.                
  10.  
  11.                 final MapPoint mp = MyUtils.getClickedMapPoint(x, y,
  12.  
  13.                                 mapView.getMapCenter(), mapView.getHeight(), mapView.getWidth(), mapView.getLatitudeSpan(), mapView.getLongitudeSpan());
  14.  
  15.                 return true;
  16.  
  17.         }
  18.  
  19. });
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


Now is still almost the same:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. this.mMapView.setOnTouchListener(new OnTouchAndLongPressListener(){
  2.  
  3.         @Override
  4.  
  5.         public void onLongPress(final View v, final float x, final float y) {
  6.  
  7.                 final MapView mapView = getMyMapView(); // Drag to local field
  8.  
  9.                 final Projection pj = mapView.getProjection();
  10.  
  11.                 final GeoPoint mp = pj.fromPixels((int)x, (int)y);
  12.  
  13.         }
  14.  
  15.  
  16.  
  17.         @Override
  18.  
  19.         public boolean onTouchEvent(final View v, final MotionEvent moEv) { return false; }
  20.  
  21. });
Parsed in 0.036 seconds, using GeSHi 1.0.8.4


Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Top

Postby rciovati » Mon Jan 04, 2010 1:02 am

Hi! Thank you very much for this tutorial... is what i need! But it doesn't works for me :(

I pasted all my code below in the hope that you can give me an opinion:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class CreateEventMap extends MapActivity {
  3.  
  4.  
  5.  
  6.         MapView mappa;
  7.  
  8.         MapController mapCtr;
  9.  
  10.         Event event;
  11.  
  12.         Location location;
  13.  
  14.         String login;
  15.  
  16.         GeoPoint touchedPoint;
  17.  
  18.  
  19.  
  20.         public void onCreate(Bundle savedInstanceState) {
  21.  
  22.                 super.onCreate(savedInstanceState);
  23.  
  24.                 setContentView(R.layout.mappa);
  25.  
  26.  
  27.  
  28.                 Bundle b = getIntent().getExtras();
  29.  
  30.                 this.location = b.getParcelable("location");
  31.  
  32.                 this.login = b.getString("login");
  33.  
  34.  
  35.  
  36.                 mappa = (MapView) findViewById(R.id.map);
  37.  
  38.  
  39.  
  40.                 mappa.setOnTouchListener(new OnTouchAndLongPressListener(mappa) {
  41.  
  42.  
  43.  
  44.                         @Override
  45.  
  46.                         public boolean onTouchEvent(View v, MotionEvent moEv) {
  47.  
  48.                                 Toast.makeText(CreateEventMap.this, "asd", Toast.LENGTH_SHORT)
  49.  
  50.                                 .show();
  51.  
  52.                                 return false;
  53.  
  54.                         }
  55.  
  56.  
  57.  
  58.                         @Override
  59.  
  60.                         public void onLongPress(View v, float x, float y) {
  61.  
  62.                                 Toast.makeText(CreateEventMap.this, "lol", Toast.LENGTH_SHORT)
  63.  
  64.                                 .show();
  65.  
  66.                         }
  67.  
  68.                 });
  69.  
  70.  
  71.  
  72.                 mapCtr = mappa.getController();
  73.  
  74.  
  75.  
  76.                 MyLocationOverlay myLocationOverlay = new MyLocationOverlay();
  77.  
  78.                 mappa.getOverlays().add(myLocationOverlay);
  79.  
  80.                 mappa.setBuiltInZoomControls(true);
  81.  
  82.                 mapCtr.setCenter(new GeoPoint((int) (location.getLatitude() * 1E6),
  83.  
  84.                                 (int) (location.getLongitude() * 1E6)));
  85.  
  86.  
  87.  
  88.                 mapCtr.setZoom(17);
  89.  
  90.  
  91.  
  92.         }
  93.  
  94.  
  95.  
  96.         @Override
  97.  
  98.         protected boolean isRouteDisplayed() {
  99.  
  100.                 // TODO Auto-generated method stub
  101.  
  102.                 return false;
  103.  
  104.         }
  105.  
  106.  
  107.  
  108.         class MyLocationOverlay extends Overlay {
  109.  
  110.  
  111.  
  112.                 public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
  113.  
  114.                                 long when) {
  115.  
  116.  
  117.  
  118.                         super.draw(canvas, mapView, shadow);
  119.  
  120.  
  121.  
  122.                         Paint paint = new Paint();
  123.  
  124.  
  125.  
  126.                         Projection projection = mapView.getProjection();
  127.  
  128.  
  129.  
  130.                         Point point = new Point();
  131.  
  132.  
  133.  
  134.                         GeoPoint myLocPoint = new GeoPoint(
  135.  
  136.                                         (int) (location.getLatitude() * 1E6), (int) (location
  137.  
  138.                                                         .getLongitude() * 1E6));
  139.  
  140.  
  141.  
  142.                         projection.toPixels(myLocPoint, point);
  143.  
  144.  
  145.  
  146.                         Bitmap bmp = BitmapFactory.decodeResource(getResources(),
  147.  
  148.                                         R.drawable.io);
  149.  
  150.                         canvas.drawBitmap(bmp, point.x - 25, point.y - 25, paint);
  151.  
  152.                         return true;
  153.  
  154.  
  155.  
  156.                 }
  157.  
  158.  
  159.  
  160.         }
  161.  
  162.  
  163.  
  164. }
  165.  
  166.  
Parsed in 0.042 seconds, using GeSHi 1.0.8.4


I copied your code in a separate file and i removed the boolean parameter (setting it to true) and added a MapView parameter for my needs.
Behavior that should have is that when I hold down for more than a second you should see the toast with the word "lol". instead, you see only "asd" at the first click and nothing else.

Thanks very much
Regards
rciovati
Developer
Developer
 
Posts: 25
Joined: Mon Jan 04, 2010 12:52 am
Location: Milano (Italy)

Re: Replacement for MapView's OnLongPressListener (from m5rc

Postby I82Much » Fri Jul 23, 2010 9:05 pm

Unfortunately the current implementation is flawed - this is not exactly the way a LongPress usually fires. If you keep your finger static on the view (pressing it), the callback is only called *after* you release your finger, or when you move it. Not during the hold phase. Which is precisely when you would want it called
I82Much
Freshman
Freshman
 
Posts: 2
Joined: Fri Jul 02, 2010 5:53 pm

Re: Replacement for MapView's OnLongPressListener (from m5rc

Postby dayerman » Thu Mar 31, 2011 6:08 pm

Hello,

As I82Much said the event is not a proper longClickListener, as you have to rise the finger to launch the ACTION_UP event. It should be everything done in the ACTION_DOWN event. I have used for that a Thread which is checking if the time elapsed is bigger that the threshlold and also is controled by a volatile varible "stop" which varies depending of the events.

Code: Select all
@Override
   public final boolean onTouch(final View v, final MotionEvent moEv) {
      
      final int action = moEv.getAction();

      final int x = (int) moEv.getX();
      final int y = (int) moEv.getY();

      switch (action) {

      case MotionEvent.ACTION_CANCEL:
         mLongPressTriggeredThisMotion = false;
         break;

      case MotionEvent.ACTION_MOVE:
            Log.d("hilo","Lanza el evento MOVE");   
            final int dx = mDownX - x;
            final int dy = mDownY - y;
            mMovedFar = dx * dx + dy * dy > LONGPRESS_MAXDIST_POW2;
            if(mMovedFar)
               ht.requestStop();
            Log.d("hilo","ACTION_MOVE mMovedFar = "+ mMovedFar);
         break;

      case MotionEvent.ACTION_UP:
            Log.d("hilo","Lanza el evento UP");
            mMovedFar = true;
            Log.d("hilo","ACTION_UP mMovedFar = "+ mMovedFar);
            ht.requestStop();
         break;

      case MotionEvent.ACTION_DOWN:
         Log.d("hilo","Lanza el evento DOWN");
         mMovedFar = false;
         mDownX = (int) x;
         mDownY = (int) y;
         mLongPressTriggeredThisMotion = false;
         ht = new HoldDown(x, y, v);
         ht.start();
         break;

      }
      return onTouchEvent(v, moEv);
   }
   
   private class HoldDown extends Thread{
      int x, y;
      View v;
      private volatile boolean stop = false;
      
      HoldDown(int x, int y, View v){
         this.x = x;
         this.y = y;
         this.v = v;
      }   
      
      public void run(){                  
         long t1 = System.currentTimeMillis();
         long et = t1 + LONGPRESS_DOWNTIME;      
         while (!stop) {   
            Log.d("hilo","WHILE mMovedFar = "+ mMovedFar);
            long t = System.currentTimeMillis();
            if(!mLongPressTriggeredThisMotion && (t > et)){
               mLongPressTriggeredThisMotion = true;
               onLongPress(v, x, y);
               break;
            }            
            else{
               try {
                  Thread.sleep(200);
               } catch (InterruptedException e) {                  
                  e.printStackTrace();
               }    
            }
         }      
      }
      public void requestStop() {
         stop = true;
         this.stop();                  
      }      
   }   
dayerman
Once Poster
Once Poster
 
Posts: 1
Joined: Wed Mar 30, 2011 4:40 pm

Top

Return to SDK/ADT/Emulator Problems

Who is online

Users browsing this forum: No registered users and 4 guests