I'm working on the android app. In my app i want to move from first activity to second activity by swiping and by click on the tab button.
so please tell me how i can use the swipe in my app for moving to next activity when i swap from Right to left and come back on first activity when i swap Left to right.
Thanks.
You can use a GestureDector to get callbacks for left and right swipe motion.
http://developer.android.com/reference/android/view/GestureDetector.html
let your activity implement OnGestureListener
and then override this method
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
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) {
Intent i=new Intent(GroupScreen.this,TimeLineScreen.class);
i.putExtra("clear", true);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
overridePendingTransition( R.anim.slide_in_left, R.anim.slide_out_left );
} catch (Exception e) {
// nothing
}
return true;
}
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
I implemented my gesture listener according to this topic: ListView Horizontal Fling Gesture
however, I can see that list scrolling is slower, sometimes (when you scroll very slowly) it blocks too.
I think the problem is in the listener: it takes time to compute values and so get the actual "left to right" fling I'm searching for...isn't there a more efficient way?
edit
Problem is here:
#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;
}
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
System.out.println("right to left");
animatedStartActivity(0);
// right to left swipe
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
System.out.println("left to right");
animatedStartActivity(1);
}
return false;
}
evaluation of this method takes time
edit2:
I guess problem is because listview already has its own gesture listener and attaching mine overrides it. It is a problem because listview gesture listener takes in account speed and acceleration too, to give a nice moving effect. My listener is pretty raw, so list scrolling is not smooth anymore..
Even if my onFLing method always returns false (so it does not consume the event) list scrolling is affected...
edit3:
Ok maybe I found the solution but I need your help!
I can set the onTouchListener on the container layout, problem is that listview actually overrides parent's onTouch so I need to reverse the situation: onTouchEvent on listview has to be intercepted by the parent, so that returning false it is brougth to listview
SOLVED!!!
Problem was that ListView's onTouchEvent performed some other operations! So I extended ListView:
public class FlingListView extends ListView{
private GestureDetector detector; //this is my detector
public void setDetector(GestureDetector detector){
this.detector = detector;
}
public FlingListView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public FlingListView(Context context,AttributeSet set) {
super(context,set);
// TODO Auto-generated constructor stub
}
public FlingListView(Context context,AttributeSet set, int a) {
super(context,set,a);
// TODO Auto-generated constructor stub
}
//here I do the magic
#Override
public boolean onTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
super.onTouchEvent(ev); //I always do the list on touch event
return(detector.onTouchEvent(ev)); //..but I return the detector!
}
}
I don't know if this is the best solution but still...it works!
I have a viewflipper which includes a number of layouts. Each layout has a scrollview as the root.
Below the viewflipper I have a horizontal scrollview which contains textviews which acts as a navigation bar.
My original issue was that the fling stopped working as soon as I added a scrollview but I added the following code:
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
super.dispatchTouchEvent(ev);
return gestureDetector.onTouchEvent(ev);
}
And the scrolling now works along with the fling.
The only issue I have now though is that the HSV nav bar now acts a little strange. Sometimes when I try to slide it across, to select new contents, the HSV springs back to where it was. Other times the HSV thinks I want to fling and moves to the next contents. This is of course dependant of the speed I try to scroll it.
I want the nav bar to work independently of the flipper.
I'm trying to understand the code to fix it myself but not getting anywhere.
I have the following in my onCreate:
gestureDetector = new GestureDetector(new MyGestureDetector());
gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}};
I have the MyGestureDetector class:
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) {
flipper.setInAnimation(flip_in_from_right);
flipper.setOutAnimation(flip_out_to_left);
flipper.showNext();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
flipper.setInAnimation(flip_in_from_left);
flipper.setOutAnimation(flip_out_to_right);
flipper.showPrevious();
}
} catch (Exception e) {
// nothing
}
And then the override:
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
super.dispatchTouchEvent(ev);
return gestureDetector.onTouchEvent(ev);
}
Can anyone shed any light on this?
Where exactly is your HSV? Is it pinned to the bottom of the screen? If so, here's what I would do. Within your onFling event, check the Y position of the fling and make sure it's not within your HSV. If it is, then return false and you should be good to go.
I have a ViewFlipper which holds a single ImageView. i want to be able to swipe to change the image / view, and click the image to play a sound.
I have a GestureDetector which is handling OnFling to change the view. I tried to put an onClickListener to the imageview, which worked but stopped the OnFling working.
Lastly, I added an onSingleTapConfirmed to my GestureDetector. This worked, however it registers a click anywhere in the Activity not just the ImageView.
Can anyone suggest how to narrow down the onSingleTapConfirmed to just work on the Imageview?
Here's my code so far:
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) {
Log.v("Swipe", "Right to Left");
viewFlipper.setInAnimation(slideLeftIn);
viewFlipper.setOutAnimation(slideLeftOut);
viewFlipper.addView(nextImage(true));
viewFlipper.showNext();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Log.v("Swipe", "Left to Right");
viewFlipper.setInAnimation(slideRightIn);
viewFlipper.setOutAnimation(slideRightOut);
viewFlipper.addView(nextImage(false));
viewFlipper.showNext();
}
} catch (Exception e) {
// nothing
}
return false;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e)
{
// TODO Auto-generated method stub
Log.v("SingleTap", "OnSingleTapConfirmed Run");
return super.onSingleTapConfirmed(e);
}
}
private View nextImage(boolean righttoleft) {
ImageView imgv1 = new ImageView(this);
if(righttoleft == true)
{
Uri image = Uri.parse("android.resource://com.owentech.brainybaby/drawable/" + variables.letters[variables.currentpos]);
imgv1.setImageURI(image);
imgv1.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
return imgv1;
}
I had encountered this problem in the past.
Maybe you can try to implement single tap by setting an OnTouchListener to ViewFlipper, thus, the ViewFlipper will be the only touch event receiver. Then write the playing sound code in onTouch function. Finally, set onTouch function's return value to false for the sake of keeping the onFling working.
viewFlipper.setOnTouchListener(new OnTouchListener()
{
#Override
public boolean onTouch(View view, MotionEvent e) {
// TODO Auto-generated method stub
switch(e.getActionMasked())
{
case MotionEvent.ACTION_DOWN:
//put the playing sound code here.
break;
}
return false; //means that the listener dosen't consume the event
}
}
);
It's just a simple solution to solve this problem. If you want to achieve more complicated function such as avoiding sound playing when finger is swiping on the screen to change the view, you have to take more effort to distinguish gestures, e.g. calculate the time between ACTION_DOWN event and ACTION_UP event and play the sound if it's less than 300ms.
I hope this will be helpful to you. :)
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.