Adding Fling Gesture to an image view - Android
Okay I have been referencing the code here: Fling gesture detection on grid layout
but just can not get开发者_运维知识库 it to work. In my main activity I have a simple image defined. I want to detect a fling on the image. Here is my code below. The onclick method at the bottom is empty. Is it because of this? I left it blank because in the other code sample its not what I want. I just want a simple toast to pop up saying fling right or fling left.
public class GestureRightLeft extends Activity implements OnClickListener {
ImageView peek;
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
peek =(ImageView) findViewById(R.id.peek);
peek.setImageResource(R.drawable.bluestrip);
gestureDetector = new GestureDetector(new MyGestureDetector());
gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}
};
}
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(GestureRightLeft.this, "Left Swipe", Toast.LENGTH_SHORT).show();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(GestureRightLeft.this, "Right Swipe", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
// nothing
}
return false;
}
}
@Override
public void onClick(View v) {}
}
Here's the simpliest working version of flinger I can think of. You can actually tie it to any component, not only ImageView.
public class MyActivity extends Activity {
private void onCreate() {
final GestureDetector gdt = new GestureDetector(new GestureListener());
final ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(final View view, final MotionEvent event) {
gdt.onTouchEvent(event);
return true;
}
});
}
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private class GestureListener extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
return false; // Right to left
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
return false; // Left to right
}
if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
return false; // Bottom to top
} else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
return false; // Top to bottom
}
return false;
}
}
}
No activity onClickListener though (if you don't need to catch any onclick actions) It captures not only horizontal, but vertical also (just delete vertical part if you don't need it), and horizontal swipes have priority as you can see. In places where method returns (nad where my comments are) just call your method or whatever :)
Try this
imageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return false;
}
return true;
}
});
imageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return !gestureDetector.onTouchEvent(event);
}
});
some of the precondition
1) setonClick method
image.setOnClickListener(this);
2) set your gesture detection in onTouch()
image.setOnTouchListener(new OnTouchListener() {
GestureDetector gestureDetector = new GestureDetector(new SwingGestureDetection((mContext),image,a));
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
3) create SwingGestureDetection class and implement all method
@Override
public boolean onFling(MotionEvent start, MotionEvent finish, float arg2,float arg3) {
if (start.getRawX() < finish.getRawX()) {
System.out.println("next...swing");
} else {
System.out.println("previois...swing");
}
}
4) pass your imageview in constructor
public SwingGestureDetection(Context con,ImageView image,int pos) {
mContext = con;
this.image = image;
this.position = pos;
}
This is perfect work for me.if any query then put comment.
Try to read: http://illusionsandroid.blogspot.com/2011/05/adding-fling-gesture-listener-to-view.html
It allow you to separate your activity implementation from your custom listener. It is simply a refactoring of the solution reported by Alex Orlov
If you dont like to create a separate class or make code complex,
You can just create a GestureDetector variable inside OnTouchListener and make your code more easier
namVyuVar can be any name of the View on which you need to set the listner
namVyuVar.setOnTouchListener(new View.OnTouchListener()
{
@Override
public boolean onTouch(View view, MotionEvent MsnEvtPsgVal)
{
flingActionVar.onTouchEvent(MsnEvtPsgVal);
return true;
}
GestureDetector flingActionVar = new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener()
{
private static final int flingActionMinDstVac = 120;
private static final int flingActionMinSpdVac = 200;
@Override
public boolean onFling(MotionEvent fstMsnEvtPsgVal, MotionEvent lstMsnEvtPsgVal, float flingActionXcoSpdPsgVal, float flingActionYcoSpdPsgVal)
{
if(fstMsnEvtPsgVal.getX() - lstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac)
{
// TskTdo :=> On Right to Left fling
return false;
}
else if (lstMsnEvtPsgVal.getX() - fstMsnEvtPsgVal.getX() > flingActionMinDstVac && Math.abs(flingActionXcoSpdPsgVal) > flingActionMinSpdVac)
{
// TskTdo :=> On Left to Right fling
return false;
}
if(fstMsnEvtPsgVal.getY() - lstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac)
{
// TskTdo :=> On Bottom to Top fling
return false;
}
else if (lstMsnEvtPsgVal.getY() - fstMsnEvtPsgVal.getY() > flingActionMinDstVac && Math.abs(flingActionYcoSpdPsgVal) > flingActionMinSpdVac)
{
// TskTdo :=> On Top to Bottom fling
return false;
}
return false;
}
});
});
If you're looking for a method like ImageView.setOnGestureListener, there is none. You can go look at the Android source code. Your best option is to handle it in onTouch() of the View object.
This is the simplest GestureDetector I can make.
I have a class called GenesMotionDetector.java. Here's the code for it:
package gene.com.motioneventssample;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class GenesMotionDetector extends Activity implements GestureDetector.OnGestureListener {
private GestureDetector gestureScanner;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nothing);
gestureScanner= new GestureDetector(getBaseContext(),this);
}
@Override
public boolean onTouchEvent(MotionEvent me) {
System.out.println("Inside onTouchEvent() of GenesMotionDetector.java");
return gestureScanner.onTouchEvent(me);
}
@Override
public boolean onDown(MotionEvent e) {
System.out.println("Inside onDown() of GenesMotionDetector.java");
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
System.out.println("Inside onFling() of GenesMotionDetector.java");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
System.out.println("Inside onLongPress() of GenesMotionDetector.java");
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
System.out.println("Inside onScroll() of GenesMotionDetector.java");
return true;
}
@Override
public void onShowPress(MotionEvent e) {
System.out.println("Inside onShowPress() of GenesMotionDetector.java");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
System.out.println("Inside onSingleTapUp() of GenesMotionDetector.java");
return true;
}
}
The corresponding XML layout file for that class is nothing.xml. Here's the code for it:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screen"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:background="#17528c"
android:text="testing"
android:layout_width="100dp"
android:layout_height="200dp" />
<ImageView
android:id="@+id/image"
android:background="#f8af20"
android:layout_width="100dp"
android:layout_height="200dp" />
</LinearLayout>
Now, taking the simplest GestureDetector I can make (from above) and modifying it for what you want, I get this:
package gene.com.motioneventssample;
import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.ImageView;
public class GenesMotionDetector3 extends Activity implements GestureDetector.OnGestureListener {
private GestureDetector gestureScanner;
ImageView mView3;
View.OnTouchListener gestureListener;
MotionEvent initialME, finalME;
private VelocityTracker mVelocityTracker = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nothing);
mView3 = (ImageView) findViewById(R.id.image);
// Gesture detection
gestureScanner = new GestureDetector(getBaseContext(), this);
gestureListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
initialME= event;
if(mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
}
else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
// When you want to determine the velocity, call
// computeCurrentVelocity(). Then call getXVelocity()
// and getYVelocity() to retrieve the velocity for each pointer ID.
mVelocityTracker.computeCurrentVelocity(1000);
break;
case MotionEvent.ACTION_UP:
finalME=event;
break;
case MotionEvent.ACTION_CANCEL:
// Return a VelocityTracker object back to be re-used by others.
mVelocityTracker.recycle();
break;
}
return onFling(initialME, finalME, mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
//return false;
}
};
mView3.setOnTouchListener(gestureListener);
}
@Override
public boolean onTouchEvent(MotionEvent me) {
System.out.println("Inside onTouchEvent() of GenesMotionDetector.java");
return gestureScanner.onTouchEvent(me);
}
@Override
public boolean onDown(MotionEvent e) {
System.out.println("Inside onDown() of GenesMotionDetector.java");
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
System.out.println("Inside onFling() of GenesMotionDetector.java");
System.out.println("e1= "+ e1);
System.out.println("e2= "+ e2);
System.out.println("velocityX= "+ velocityX);
System.out.println("velocityY= "+ velocityY);
return true;
}
@Override
public void onLongPress(MotionEvent e) {
System.out.println("Inside onLongPress() of GenesMotionDetector.java");
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
System.out.println("Inside onScroll() of GenesMotionDetector.java");
return true;
}
@Override
public void onShowPress(MotionEvent e) {
System.out.println("Inside onShowPress() of GenesMotionDetector.java");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
System.out.println("Inside onSingleTapUp() of GenesMotionDetector.java");
return true;
}
}
You might as well just handle everything in onTouch(). I'm basically getting the gestures in onTouch and passing it to onFling().
Design your layout with ImageView.
Add setOnTouchListener
to imageView.imageview.setOnTouchListener(this)
.add unimplemented method View.OnTouchListener
.Then onTouch
method you can implemtn your guesture logic.This sample tells you left to right and right to left guesture,
float x1,x2;
float y1, y2;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch ( event.getAction() ){
case MotionEvent.ACTION_DOWN:{
x1 = event.getX();
y1 = event.getY();
break;
}
case MotionEvent.ACTION_UP:{
x2 = event.getX();
y2 = event.getY();
if ( x1<x2 ) {
//implement what you need to do here
}
if ( x1>x2 ) {
//implement what you need to do here
}
break;
}
}
return false;
}
Quick example for kotlin:
val flingGesture = GestureDetector(requireContext(), object : GestureDetector.SimpleOnGestureListener() {
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
// your action here
return true
}
})
Set to any view:
imageView.setOnTouchListener{ _, motionEvent ->
flingGesture.onTouchEvent(motionEvent)
return@setOnTouchListener true
}
精彩评论