I can make a gesture which detects a movement when the user touches the screen from left to right.
But I don't know how to make the image move along with that movement.
The purpose of this is to do a lock screen inside my application like the iPhone lock/unlock feature.
I guess I have to do something like image_swipe.setAnimate... or something.
If anyone has any idea, please let me know.
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;
#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(e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show();
//i would like to make ImageView "image_swipe" move along with gesture
}
} catch (Exception e) {
}
return true;
}
See the below link, it may help you. The image movement when you swipe (onFling) the screen is available in this example.
CoverFlow Widget Example
Related
I have created 5 activities, each has a ListView containing only images. I have used a simple swipe animation to change activities.
Here is the relevant code:
#Override
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return super.onTouchEvent(event);
}
private void onLeftSwipe() {
Intent intent = new Intent(HimachalActivity.this, IndianWildlifeActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_left_in, R.anim.slide_left_out);
}
private void onRightSwipe() {
Intent intent = new Intent(HimachalActivity.this, BaseActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_right_in, R.anim.slide_right_out);
}
private class SwipeGestureDetector extends GestureDetector.SimpleOnGestureListener {
// Swipe properties, you can change it to make the swipe
// longer or shorter and speed
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 200;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
try {
float diffAbs = Math.abs(e1.getY() - e2.getY());
float diff = e1.getX() - e2.getX();
if (diffAbs > SWIPE_MAX_OFF_PATH)
return false;
// Left swipe
if (diff > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
HimachalActivity.this.onLeftSwipe();
// Right swipe
} else if (-diff > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
HimachalActivity.this.onRightSwipe();
}
} catch (Exception e) {
Log.e("BaseActivity", "Error on gestures");
}
return false;
}
}
The problem is that the next activity or previous activity opens only after full swipe and the animation does not feel that smooth.
I want an animation in which the next activity or previous activity starts revealing itself as soon as I start swiping. Is there any built-in animation that can be applied. If not, please point me to any relevant resources for creating one myself, possibly, one which does not require me to modify the existing code much. Thanks.
As far as I know this feature is easily available in Lollipop material design module.
I reckon, it would be easier in case you follow #Whitney 's advice. Put your fragments in view pager as described here: http://developer.android.com/training/animation/screen-slide.html
The reason it is not working with your current implementation is that the device makes sense of fling gesture only after you have flinged. Thereafter, the animation takes place. Fling is not detected in real time. In case you want to implement real time fling, you might have to override touch events as described here: http://developer.android.com/training/custom-views/making-interactive.html
How to create an image slider in eclipse?
i want, when a finger moves from left to right or from right to left on imageView, I want to change the photo.
No need to do any custom thing.As Android provides the facility like this in ViewFlipper class.It is actually made for it.
View Flipper:-
Simple ViewAnimator that will animate between two or more views that
have been added to it. Only one child is shown at a time. If
requested, can automatically flip between each child at a regular
interval.
Its very nice and also built in support for animation so just use this for this purpose.
To implement the ViewFlipper in your application I am sharing some good tutorials..
http://javatechig.com/android/android-viewflipper-example
http://www.yogeshblogspot.com/android-viewflipper-example/
http://learnandroideasily.blogspot.in/2013/06/android-viewflipper-example.html
You can also get more info at here.
http://developer.android.com/reference/android/widget/ViewFlipper.html.
Enjoy..!
View Pager refer this is one option, otherwise you can add a simple gesture listener to your image view.
//Adding gesture listener to image view.
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;
}
});
//The gesture listener class
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) {
//load previous image here
return false; // Right to left
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//load next image here
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;
}
}
I have a calendar with gridview and changing months should be working with gestures (flings) on the gridview. A fling from left to right goes to the previous month, and a fling from right to left should go to the next month. The first one works, the second one does not always work, it detects the left to right fling instead(40-50%). I am using a standard onfling function and I have two other buttons with arrows that indicate another option to change months. Those buttons work very well, and if I use the onfling function on an imageview or textview, or anything that isnt a gridview, it works very well.
class MyGestureDetector extends SimpleOnGestureListener
{
private static final int SWIPE_MIN_DISTANCE = 40;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
#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;
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
{
//Log.i("Swipe", "Right to Left");
//Log.i("Swipe", "Swipe rowid2" + selected_row_id2 + "set to true");
gestureDirection = "rtl";
Toast toast = Toast.makeText(getApplicationContext(), "RTL", 3500);
toast.show();
return true;
}
else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
{
//Log.i("Swipe", "Left to Right");
//Log.i("Swipe", "Swipe rowid" + selected_row_id2 + "set to false");
gestureDirection = "ltr";
Toast toast2 = Toast.makeText(getApplicationContext(), "LTR", 3500);
toast2.show();
return true;
}
return false;
}
}
As I mentioned it is a standard onFLing function, but the fling from right to left sometimes behaves as if I flinged from left to right and instead of changing to the next month it goes back to the previous month. It should impossible since (e1.getX() - e2.getX()) should not allow this. I noticed that if my fling from right to left is short (but of course bigger than the SWIPE_MIN_DISTANCE) it always work, but for example if my fling's size is almost 3/4 screen it sometimes behaves incorrect. Another interesting thing, it always works on emulator, the problem is detected on phone.
Any one had this problem?
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Gesture detection and ScrollView issue
EDIT: question with full code asked here.
I've got a layout with a child. I set a gesture listener to detect horizontal swipe on the layout. When the layout is a LinearLayout the swipe is properly detected, but when it's a ScrollView, it's not. I guess the gesture is first detected by the ScrollView and is not propagated to its ascendants, but I don't know how to solve it.
Here's my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<ImageView android:layout_width="320dp" android:layout_height="30dp"
android:src="#drawable/header"/>
<ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content">
<!-- stuff -->
</ScrollView>
</LinearLayout>
I set the following listener to my layout:
class ProductGestureListener extends SimpleOnGestureListener {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
final int SWIPE_MIN_DISTANCE = 120;
final int SWIPE_MAX_OFF_PATH = 250;
final int SWIPE_THRESHOLD_VELOCITY = 200;
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
if(e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// show previous item
} else if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// show next item
}
} catch (Exception e) {
}
return false;
}
}
If you want the whole Activity to be swipeable horizontally you can use the following as a super class for your Activity:
public abstract class SwipeActivity extends Activity {
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;
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
gestureDetector = new GestureDetector( new SwipeDetector() );
}
private class SwipeDetector extends SimpleOnGestureListener {
#Override
public boolean onFling( MotionEvent e1, MotionEvent e2, float velocityX, float velocityY ) {
// Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH,
// then dismiss the swipe.
if( Math.abs( e1.getY() - e2.getY() ) > SWIPE_MAX_OFF_PATH )
return false;
// Swipe from right to left.
// The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
// and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
if( e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs( velocityX ) > SWIPE_THRESHOLD_VELOCITY ) {
next();
return true;
}
// Swipe from left to right.
// The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
// and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
if( e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs( velocityX ) > SWIPE_THRESHOLD_VELOCITY ) {
previous();
return true;
}
return false;
}
}
#Override
public boolean dispatchTouchEvent( MotionEvent ev ) {
// TouchEvent dispatcher.
if( gestureDetector != null ) {
if( gestureDetector.onTouchEvent( ev ) )
// If the gestureDetector handles the event, a swipe has been
// executed and no more needs to be done.
return true;
}
return super.dispatchTouchEvent( ev );
}
#Override
public boolean onTouchEvent( MotionEvent event ) {
return gestureDetector.onTouchEvent( event );
}
protected abstract void previous();
protected abstract void next();
}
All you need to do is implement the next() and previous() methods after extending SwipeActivity.
I had to add
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
super.dispatchTouchEvent(ev);
return productGestureDetector.onTouchEvent(ev);
}
Add this method in your activity class which uses swiper just like the onCreate method.
The sequence of events for android is this
user performs some action
-> action is passed to parent
->if parent handles action then the action is consumed
->else the action is passed to a child
->if child handles action then the action is consumed
->else the action is passed on
this process continues until the action is consumed or all children have received the action and none of them handled it.
To detect a horizontal swipe in a scroll view and pass it to a child instead of the scroll view consuming it the event needs to be intercepted.
ie
user performs some action
-> action is passed to parent
->if horizontal swipe pass to child
-> else have the scroll view handle the action
to do this (as out lined in the top answer here: HorizontalScrollView within ScrollView Touch Handling ) a gesture detector is used in the scroll view for the sole purpose of detecting whether the gesture is horizontal or vertical.
If the gesture is horizontal then we want to intercept the event and pass it to the child.
You need to create a custom scrollview then implement a gesture detector there and call it from onInterceptTouch(). By returning true or false here we can say whether or not to consume the event here, everything you need is in that link above.
I'm trying to implement a view that has both a longClickListener and a gesture dectector. Basically, I need a button to show a view when the user long clicks on the first view, and then I want to dectect a fling motion up. I would like to make it so that the user does not have to lift their finger at all, and hit both the longclick, and the fling motion.
Here is my code for the longClickListener:
flipCard.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View view) {
answerRight.setVisibility(View.VISIBLE);
answerRight.startAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.grow_from_middle));
answerWrong.setVisibility(View.VISIBLE);
answerWrong.startAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.grow_from_middle));
return false;
}
});
Here is the code for my gesture dector:
gestureDetectorScore = new GestureDetector(new ScoreGestureDetector());
gestureListenerScore = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetectorScore.onTouchEvent(event)) {
return true;
}
return false;
}
};
private class ScoreGestureDetector extends SimpleOnGestureListener {
private static final int SWIPE_MIN_DISTANCE = 5;
private static final int SWIPE_THRESHOLD_VELOCITY = 2;
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
//if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH)
//return false;
// right to left swipe
//if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE){
Toast.makeText(AndroidOrientationSensor.this, "Up Swipe", Toast.LENGTH_SHORT).show();
}
//else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE){
Toast.makeText(AndroidOrientationSensor.this, "Down Swipe", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
// nothing
}
return false;
}
#Override
public boolean onDown(MotionEvent e1){
Toast.makeText(AndroidOrientationSensor.this, "Up Swipe", Toast.LENGTH_SHORT).show();
return true;
}
}
Finally, I am setting the gesture dectector to the the "flipCard" view like this:
flipCard.setOnTouchListener(gestureListenerScore);
Any help would be greatly appreciated.
I think the problem you're going to have is if the touch event is consumed by the button, then the second view won't receive it.
Even if it did, the fling I imagine will only get called when the user performs a fling from start to finish.
The only thing I can think of doing (despite it being very horrible / hacky) is to try and inset a fake up touch event. This might then allow the user to perform the fling, but this isn't particularly stable either.
Better way to handle it would be to have a view group consume the touch events, pass the touch events to a gesture detector to detect a long click, then set a flag within the view groups touch listener to indicate a fling is expected, then manually detect when prev y and current y go beyond a threshold. This will give you some idea of velocity but probably no where near as meaningful as the velocity provided in the onFling callback method.
What I ended up doing to solve this problem is placing a gestureDectector on the view and overriding the onDown method. This allowed me to simulate a click event. I was unable to get both a long click and a swipe event, but for my purposes the click event triggers during the swipe which seems to work well enough. Thanks to GauntFace for the inspiration.
The GestureListener also has a onLongPress event.