Drag and Drop + Fling Detector not working
Asked Answered
L

1

7

I'm trying to implement a draggable button that should also be flingable.

Unfortunately the system stops sending MotionEvents after the drag is started. Therefore the GestureDetector.OnGestureListener.onFling() method is never called.

Is there a way to intercept those events before they are consumed by the drag system?

I also tried to create my own FlingDetector, but it's not reliable across different devices and screen densities:

public class FlingDetector {

private final int MIN_FLING_SPEED = 3;

private OnFlingListener mOnFlingListener;

private float mCurrentX = 0;
private float mCurrentY = 0;
private long mLastMovementTime = 0;
private double  mCurrentVelocity = 0;

private final float mDensity;

public FlingDetector(OnFlingListener onFlingListener, Context context) {
    mOnFlingListener = onFlingListener;
    mDensity = context.getResources().getDisplayMetrics().density;
}


public void onMovementStart(float x, float y) {
    mCurrentX = x;
    mCurrentY = y;
    mLastMovementTime = System.currentTimeMillis();
    mCurrentVelocity = 0;
}

public void onMovementEnd(float x, float y) {

    long currentTime = System.currentTimeMillis();

    float distanceX = Math.abs(mCurrentX - x) / mDensity;
    float distanceY = Math.abs(mCurrentY - y) / mDensity;

    float distance = (float) Math.sqrt(Math.pow(distanceX, 2) +
            Math.pow(distanceY, 2));

    mCurrentVelocity = (distance / (currentTime - mLastMovementTime));

    if(mCurrentVelocity > MIN_FLING_SPEED) {
        mOnFlingListener.onFling((int) (mCurrentVelocity + 0.5));
    } else {
        Log.d("test", "Distance: " + distance);
        Log.d("test", "Time Delta: " + (currentTime - mLastMovementTime));
        Log.d("test", "Speed: " + mCurrentVelocity);
    }
}

public interface OnFlingListener {
    void onFling(int speed);
}

}
Labiodental answered 23/12, 2015 at 11:4 Comment(2)
I implemented something similar in a library. See the GestureDetectorCompat here. Hope it helps.Mannose
@Labiodental try to access the location while dragged....and if location changed very fast. it is flinged. try using getAction() and ACTION_DRAG_LOCATION. i don't know how you can measure speed.Vevay
C
0

You can achieve both fling and drag with a button using GestureDetector. GestureDetector is a little straight forward,its has it's own Default method for handling the following motion event.

  1. LongPress
  2. Fling
  3. onDown
  4. onShowPress
  5. onSingleTapUp
  6. onScroll

You can Implement Like this.

public class MainActivity extends AppCompatActivity {

    Button button;
    GestureDetector buttonGestureDetector;
    static final int SWIPE_MIN_DISTANCE = 60;
     static final int SWIPE_THRESHOLD_VELOCITY = 100;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=(Button) findViewById(R.id.button);

        buttonGestureDetector=new GestureDetector(this,new GestureDetector.OnGestureListener() {
          @Override
          public boolean onDown(MotionEvent e) {
              return false;
          }

          @Override
          public void onShowPress(MotionEvent e) {

          }

          @Override
          public boolean onSingleTapUp(MotionEvent e) {
              return false;
          }

          @Override
          public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
              return false;
          }

          @Override
          public void onLongPress(MotionEvent e) {
              Log.i("Drag","DragListening");
              View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(button);
              button.startDrag(null, shadowBuilder, button, 0);
              button.setVisibility(View.INVISIBLE);



          }

          @Override
          public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

              Log.i("FlingListened","FlingListened");

              if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                  Toast.makeText(MainActivity.this,"OnRightToLeft Fling",Toast.LENGTH_SHORT).show();
              }
              else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
              {
                  Toast.makeText(MainActivity.this,"OnLeftToRight Fling",Toast.LENGTH_SHORT).show();
              }
              if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {

                  Toast.makeText(MainActivity.this,"onBottomToTop Fling",Toast.LENGTH_SHORT).show();

              }
              else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
                  Toast.makeText(MainActivity.this,"OnTopToBottom Fling",Toast.LENGTH_SHORT).show();

              }
              return true;


            }
      });

        button.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                buttonGestureDetector.onTouchEvent(event);
                return false;


            }
        });

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

                int action = event.getAction();
                switch (action) {
                    case DragEvent.ACTION_DRAG_STARTED:
                        Log.d("Drag", "Drag event started");
                        break;
                    case DragEvent.ACTION_DRAG_ENTERED:
                        Log.d("Drag", "Drag event entered into "+dragView.toString());
                        break;
                    case DragEvent.ACTION_DRAG_EXITED:
                        Log.d("Drag", "Drag event exited from "+dragView.toString());
                        break;
                    case DragEvent.ACTION_DROP:
                        Log.d("Drag", "Dropped");
                        View view = (View) event.getLocalState();
                        ViewGroup owner = (ViewGroup) view.getParent();
                        owner.removeView(view);
                        LinearLayout container = (LinearLayout) dragView;
                        container.addView(view);
                        view.setVisibility(View.VISIBLE);
                        break;
                    case DragEvent.ACTION_DRAG_ENDED:
                        Log.d("Drag", "Drag ended");
                        break;
                    default:
                        break;
                }
                return true;
            }


        });

    }
}
Casta answered 1/1, 2016 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.