I am working in android. I have some functionality which is to be done on these following methods:-
1. MotionEvent.ACTION_DOWN
2. MotionEvent.ACTION_UP
3. MotionEvent.ACTION_MOVE
and i also want to do fling() on that image.
For above requirement i implemented onGestureListener and onTouchListener in my application, but these are not working properly. onTouchListener is working but onGestureListener is not working. When i remove onTouchListner code then onGestureListener is working correctly.
So please suggest me what should i do for this. I want to implement these four methods in my application.
1. MotionEvent.ACTION_DOWN
2. MotionEvent.ACTION_UP
3. MotionEvent.ACTION_MOVE
4. onFling
You can acheive this by implementing the OnGestureListener from your activity overriding the below methods
// For touch
public boolean onSingleTapUp(MotionEvent event) { return false; }
// For Fling
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
Hope this helps.
EDIT 1: Detailed explanation:
1> implement the OnGestureListener from your activity
public class MyActivity implements OnGestureListener
2> create an instance of GestureDetector:
private GestureDetector gestureScanner;
And at onCreate:
// Avoid a deprecated constructor
// (http://developer.android.com/reference/android/view/GestureDetector.html)
gestureScanner = new GestureDetector(this, this);
3> Override the below methods:
#Override
public boolean onTouchEvent(MotionEvent event) {
return gestureScanner.onTouchEvent(event);
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
/* on scroll to the next page in story */
if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// ...
}
/* on scroll to the previous page in story */
else if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// ...
}
return false;
}
#Override
public boolean onSingleTapUp(MotionEvent event) {
return false;
}
EDIT 2: For handling Move
Override the onScroll method have a look at the details here
Just as a word of advice coming from a fellow Android developer who has chased down the primrose path of the swipe or fling event... When writing a listener or trying to implement the OnGestureListener class be sure to have import android.view.GestureDetector.OnGestureListener in your imports.
Otherwise the OnGesturListener will be using a GestureOverlayView's imports and that's not what it seems you are looking for. Those are helpful especially when trying to implement gesture captures using the Gestures application and importing the saved gestures and creating a Gestures Library for your application during run time to then "predict" what the user is doing by running some fancy algorithm in the background and seeing who deviates the least from the user's input. Which turns out to be an array of locations that came in from the OS as the dragged their little stubby fingers across the flat screen... It's a different approach than just trying to capture a fling, or long press. Which seems as what the users are looking for above and not some fancy multi-press gesture capture, which this approach makes very simple. This technique is also very helpful in video games and giving possibly a "backdoor" to any people out there who like to develop games. Or in the 9-5 world, to put a Support or Admin backdoor into your mobile application to hide some settings or logs from everyday users. In which one can also use the above intended techniques but then you have to get an array of points, or locations across the screen and it gets tedious for any non-math people or self taught developers. Hope I contributed or helped anyone. No one mentioned this to me when I was learning this and I never found it in any of the several books I have read about Android also.
Related
I'm replicating my IOS App that heavily uses Pan Gesture Recognizer to Android and I couldn't find similar
Gesture recognizer. Is there such thing?
any direction is appreciated thanks
Android comes out of the box with two classes that recognize gesture. One is GestureDetector and the other is ScaleGestureDetector.
Unlike, ios, the basic gesture detector framework is limited - you can't specify dependencies, do conflict resolution or configure them by specifying touch points etc like you can in ios's UiGestureRecognizer class.
To answer your question, pan can be detected using the GestureDetector. Here is a snippet:
PanGestureListener listener = new PanGestureListener();
GestureDetector detector = new GestureDetector(context, listener);
class PanGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onScroll(MotionEvent e1,
MotionEvent e2,
float distanceX,
float distanceY) {
//YOUR "pan handler"
return true;
}
}
Now in your onTouch method just forward all the calls to detector.onTouch like this:
#Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);
return true;
}
I think what you're looking for is GestureDetector. I'm not very familiar with iOS's Pan Gesture Recognizer, but I think it does't work exactly the same way in Android. See the developer guide topic Using Touch Gestures for info on how to use the class.
I need to swipe horizontally between list of questions and their respective choices in a radio group. I have read that I have different choices such as:
1- Gesture Detector
2- ViewPage
3- ViewPage with fragments
I have tried ViewPage but I am facing different problems on how to swipe backward and indicating which choice has been checked by the user.
I need to use the easiest way to swipe forward and backward (indicating which choice has been checked)
I want to depend on Andriod methods as much as possible without storing the checked choices for example by myself since I believe that it is more optimized such methods from both run-time or code size.
Please if there are other classes that I can use, guide me on that or which of them is really the best to perform my target
I would use ViewPager with a FragmentPagerAdapter. The items of the adapter would be different instances of the same fragment. Each fragment would contain a static question text and a radio group of possible answers to the question.
ViewPager then will take care of swiping substituting one such fragment with another.
I highly recommend this Library:
ViewPagerIndicator by Jake Warton
Is very customizable.
You can easilly use the gesture detector creating a class that extend SimpleOnGestureListener that possess the onFling methods like that :
protected class ExampleGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {// User swipe vertically
}
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_MIN_VELOCITY) {// Right swipe
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_MIN_VELOCITY) {// Left swipe
}
return false;
}
}
You just have to define the variable as you want, create your gestureDetector like
gestureDetector = new GestureDetector(new ExampleGestureDetector());
And redefine the touch listener for the view you want
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View wv, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
EDIT : After testing it, it appear that it only work with scrollable item.
The best I could find on this particular issue (although I do not use a Gallery): ScrollView and Gallery interfering - doesn't really give a specific answer though. And my implementation does not use a Gallery, obviously.
Jump down to the next bold part for the interesting part
So I got Fling/Swipe/Flick/whatever you want to call it to work a while ago on my application. Inspiration was gathered from a couple of different places, some of them being "basic gesture detection" here on Stack Overflow ( Fling gesture detection on grid layout ), Code Shogun ( http://www.codeshogun.com/blog/2009/04/16/how-to-implement-swipe-action-in-android/ ) and Developing Android ( http://developingandroid.blogspot.com/2009/09/implementing-swipe-gesture.html ), but I do not use a ViewFlipper in my application. When a fling occurs I simply change the tab (wrapping around at the ends).
Now, some of my tabs contain ScrollViews. These ScrollViews obviously respond to up/down scrolls in order to let you view all data inside it, no surprise there.
The issue is that it would appear the 'scroll' function of these ScrollViews overwrite my fling gesture. I cannot fling inside a ScrollView (scroll just fine), but it works flawlessly outside them (on the same tab, on other views such as TableRow or whatever).
I had a quick look at http://blog.velir.com/index.php/2010/11/17/android-snapping-horizontal-scroll/ too, which provides a way to implement HorizontalScrollView. But it still handles gestures through a class that extends SimpleOnGestureListener (and overwrites onFling), which is the same implementation as I have (which leads me to believe it won't really help).
Source code for ScrollView from Google: http://google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/widget/ScrollView.java&d=3
Is there any way to have my implementation of Swipe and ScrollView working together effortlessly?
This is where the problem lies, I guess. ScrollView.java also uses a method called onTouchEvent and the documentation for the onTouchEvent for Activity states:
"Called when a touch screen event was
not handled by any of the views under
it. This is most useful to process
touch events that happen outside of
your window bounds, where there is no
view to receive it."
So the ScrollView does "override" it - what do I do? Is there no way to ensure both are checked? My onTouchEvent which is not hit when the onTouchEvent is handled by the ScrollView:
#Override
/** Used for swipe gestures */
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event))
return true;
else
return false;
}
More general source code below, it's probably not very vital. The gestureDetector inside my Tabs class with its associated listener:
// Gestures
gestureDetector = new GestureDetector(new MyGestureDetector());
gestureListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}
};
My gesture class which is a nested class of my Tabs class (which extends TabActivity) - it's the same as any other code you will find on this subject:
/** GestureDetector used to swipe between classes */
class MyGestureDetector extends SimpleOnGestureListener {
TabHost tabHost = getTabHost();
#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;
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// my tab code
return true;
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// my tab code
return true;
}
} catch (Exception e) {
Log.e("MyGestureDetector onFling", e.toString());
}
return false;
}
}
I would suggest you have a look at the Google I/O 2010 app source code, as their FlingableTabHost implementation would appear to have solved this problem:
http://iosched.googlecode.com/svn/trunk/src/com/google/android/apps/iosched/ui/ScheduleActivity.java
I think the key is in extending TabHost and overriding its onInterceptTouchEvent method.
In looking to solve a similar issue I am having, I came across this tid-bit:
eventsInterceptionEnabled: when set to true, this property tells the overlay to steal the events from its children as soon as it knows the user is really drawing a gesture. This is useful when there's a scrollable view under the overlay, to avoid scrolling the underlying child as the user draws his gesture
From the Android Dev site, it talks about using this attribute in the <android.gesture.GestureOverlayView> Root in your layout file.
For what it's worth, I found the onFling method very unreliable. I override the onScroll method in the SimpleGestureDetector, and define my onInterceptTouchEvent as:
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//Call super first because it does some hidden motion event handling
boolean result = super.onInterceptTouchEvent(ev);
if (this.mGestureScanner.onTouchEvent(ev)) return true;
return result;
}
I have implemented my TabActivity with different child activities:
intent = new Intent().setClass(this, MyChildTabActiviy.class);
// Initialize a TabSpec for each tab and add it to the TabHost
spec = getTabHost.newTabSpec("tag").setIndicator("indicator", getResources().getDrawable(R.drawable.icon)).setContent(intent);
getTabHost.addTab(spec);
...
So far no problems, everything works perfectly fine. I'm switching programmatically between tabs, replacing activities within tabs with ActivityGroups, etc. just as it's shown in many tutorials.
But my problem is, that when I want to check for a fling gesture my gestureDetector.onTouchEvent(event) is always returning false, thus no gesture is registrated.
This is my implementation of gestureDetector:
public class MyChildTabActiviy extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
// ... building views, controls, etc.
GestureDetector gestureDetector = new GestureDetector(this, new MyGestureDetector());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// left to right swipe and right to left swipe
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//... fling logic ...
return true;
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//... fling logic ...
return true;
}
return false;
}
}
The thing is, that this code (and also the fling detection) works perfectly fine, when I'm starting these activities (there are four basic activities, that I sometimes switch to other activities) outside of a TabActivity, e.g. as a Launcher Activity. But I can't get it to work within a TabActivity. I already tried to append the GestureDetector to the TabActivity, but it doesn't work. I tried to append the GestureDetector to specific views like some layout views or buttons, ViewFlippers, etc. but it just doesn't work.
When I'm debugging, I can see that the touch event is triggered and a motion is registered, but it just isn't evaluated as a fling or any other gesture.
So my question is, are there are any limitations regarding the usage of GestureDetectors with Tabs in Android? As I said, the gestures are registrated perfectly outside a TabActivity.
I would greatly appreciate the help of someone who knows the answer.
If there is a limitation, how could someone get a workaround for that problem?
Thanks in advance for answers.
Have a look at the answer mentioned here. He's pretty much done the same thing as you, but if you look at the first comment on the highest rated answer, Cdsboy got it working by implementing OnDown and returning true. I'm not sure why that is needed, but it worked for me.
As a complement to #Abhinav 's answer (that btw helped me too), I'd like to say that I think overriding onDown() is needed because its default implementation in SimpleOnGestureListener is to return false. Being ACTION_DOWN the first one to reach the listener, it would make it discard the event, whatever it is.
I'm playing around with an app I have written whose main activity is a TabActivity. I was considering allowing the user to navigate between tabs with a fling gesture, but I find that I can only detect flings on one of my four tabs.
public class WSGesture extends TabActivity implements OnGestureListener {
private GestureDetector gestureScanner;
#Override onCreate(Bundle savedInstanceState)
{
gestureScanner = new GestureDetector(this);
...
}
.
.
.
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
Log.v(TAG, "onFling called, velX: " + velocityX + ", velY: " + velocityY);
return true;
}
public boolean onTouchEvent(MotionEvent me)
{
return gestureScanner.onTouchEvent(me);
}
}
When I execute this code, I only see onFling being called when one particular tab is set as the current tab. For the other three, I get nothing. It's always the third out of four, if that matters.
One thing that has worked for me in the past is implementing onDown() and returning true...
When doing this though, be careful... I have found that the behavior when doing this is different between the 1.x and 2.x versions of Android when using your onGestureListener to handle other things like single clicks... so be sure to thoroughly test your app when making changes like this.
If you are only using onFling then you "should" be ok... but test it just to be safe.