I want to animate onFling events on my list view.
The animation works fine, but at the wrong row.
For example:
ListView with only one item, the animation work as expected.
ListView with two items: with the gesture is make on the first item the second one is animated and vice-versa.
ListView with three items: with the gesture is make on the first item se last one is animated , on the second item the second item is animated (as expected), on the last item the first item is animated.
CODE:
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
int position = listView.pointToPosition(Math.round(e1.getX()),
Math.round(e1.getY()));
View row = listView.getChildAt(position);
TranslateAnimation anim = null;
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH || row == null)
return true;
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF,1,Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0);
this.handleSwipe.onHandleSwipeLeft(position);
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF,-1,Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0);
this.handleSwipe.onHandleSwipeRight(position);
}else{
return true;
}
anim.setDuration(500);
row.startAnimation(anim);
return true;
}
OBS:
Already debug, and the position and row are always right.
I'm using api level 7.
The code work fine on android 4.2
Guilherme, probably the code:
int position = listView.pointToPosition(Math.round(e1.getX()),
Math.round(e1.getY()));
Isn't returning the row id 3. Can you confirm that?
Related
I'm trying to add 'kinetic' move in Y-axis from top of the screen to bottom (and vice versa) to custom layout displayed above all apps using the window manager.
I tried to do it in this way:
private void animateFlingInYAxis(View view) {
FlingAnimation fling = new FlingAnimation(view, DynamicAnimation.SCROLL_Y);
fling.setStartValue(0.9F);
fling.setStartVelocity(0f);
//fling.setMinValue(0.5F);
fling.setFriction(0.2F);
fling.start();
}
But the following result is no working correctly. I tried to change values SCROLL_Y to TRANSLATION_Y and set a custom range of values but without luck.
Action is processed in ACTION_MOVE event in this way:
case MotionEvent.ACTION_MOVE:
params.y = initialY + (int) (event.getRawY() - initialTouchY);
if(isMovingInYAxis((int) initialTouchY ,(int) event.getRawY())) {
windowManager.updateViewLayout(view, params);
animateFlingInYAxis(view);
}
break;
I would like to ask how to animate moving in Y-axis in the right way?
Many thanks for any advice.
Edit1: After setting setStartVelocity(2000); seems to be working better, but the view is partially hiding (see screenshot below).
Edit2: I Implemented GestureDetector.OnGestureListener in Custom View, now I am able to catch fling and scroll events. In onFling method, I am able to recognize direction of fling gesture (TOP_BOTTOM, BOTTOM_TOP), but I am not able to to do the animation of view of given direction.
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Logger.d("onFling");
if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
Logger.d("Bottom to top");
animateFlingInYAxis(view, "BOTTOM_TOP");
return false; // Bottom to top
} else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
Logger.d("Top to bottom");
animateFlingInYAxis(view, "TOP_BOTTOM");
return false; // Top to bottom
}
return false;
}
private void animateFlingInYAxis(View view, String type) {
FlingAnimation fling = new FlingAnimation(view, DynamicAnimation.TRANSLATION_Y);
if(type.equals("BOTTOM_TOP")) {
fling.setStartValue(100); //WHICH PARAMS TO PASS?
fling.setMinValue(480); //WHICH PARAMS TO PASS?
fling.setMaxValue(0); //WHICH PARAMS TO PASS?
} else{
fling.setStartValue(470);
fling.setMinValue(480);
fling.setMaxValue(0);
}
fling.setStartVelocity(2000);
fling.setFriction(0.8F);
fling.start();
I have a simple activity which has a root layout.The root layout contains a recyclerview. Recyclerview will contain 20 items created from items.xml ,
which consists of 3 text views.Here items.xml represent single item in the recyclerview.
The recycler view can be scrolled both the ways , it is kind a loop of the items between 1 to 20.
I have a requirement to smoothscroll only 4 items , irrespective of the velocity of the swipe/fling.
Approaches which i have tried many approaches but coudn't succeed till now. If anyone can give any suggestions , that would be very helpful.
SnapHelper - this seems to snap only the item which is in the center.
Using gesture detector - the gestures are getting detected for all the actions , but i am unable to prevent the recyclerview's default scrolling behaviour.
The main issue is the over-scrolling of recycler view due to varing velocities of user scrolls and flings.
Here is my set up for the gesture detector.
public myRecyclerTouchListner(final Context context, final RecyclerView recycleView,
final LinearLayoutManager linearLayoutManager,
final ClickListener clicklistener){
final ViewConfiguration vc = ViewConfiguration.get(context);
final int swipeMinDistance = vc.getScaledPagingTouchSlop();
final int swipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();
final int swipeMaxOffPath = vc.getScaledTouchSlop();
this.clicklistener=clicklistener;
simpleGestureDetector =new GestureDetector(context,new GestureDetector.SimpleOnGestureListener( ){
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.d("try", "on Fling called");
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE &&
Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//From Right to Left
recycleView.smoothScrollToPosition(linearLayoutManager.
findLastCompletelyVisibleItemPosition() + Constants.spanLength);
return true;
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE &&
Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//From Left to Right
recycleView.smoothScrollToPosition(linearLayoutManager.
findFirstCompletelyVisibleItemPosition() - Constants.spanLength);
return true;
}
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return true;
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
Log.d("Try", "Long press gesture");
View child=recycleView.findChildViewUnder(e.getX(),e.getY());
if(child!=null && clicklistener!=null){
clicklistener.onLongClick(child,recycleView.getChildAdapterPosition(child));
}
}
});
I think your problem is that scrolling is starting from last visible position where Fling is detected and that mess up the things.
Try with global variable for example int lastScrolledPosition = 0;.
And OnFling recycleView.smoothScrollToPosition(lastScrolledPosition + Constants.spanLength);
I thing this should do the trick. You should change if lastScrolledPosition < Recycleritems count.
It turns out I had to use Snaphelper for custom scroll behavior in case wherein I need control over programmatic scroll and user-scroll(fling).
This was exactly what I was looking for:
How to snap RecyclerView items so that every X items would be considered like a single unit to snap to?
I hope it will be helpful :)
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?