Viewflipper animation doesn't work on first swipe
Asked Answered
I

3

10

On my main activity, I have a viewflipper with three child views. After the app is first started, when I do the first right to left swipe, the view changes, but it does not have the slide animation. After the first swipe, the animation works as expected when swiping in either direction. I am following this tutorial. The code I use is:

 public boolean onTouchEvent(MotionEvent touchevent)
{
    switch (touchevent.getAction())
    {
        // when user first touches the screen
        case MotionEvent.ACTION_DOWN:
        {
            lastX = touchevent.getX();
            break;
        }
        case MotionEvent.ACTION_UP:
        {
            float currentX = touchevent.getX();

            // left to right swipe
            if (lastX < currentX)
            {
                if (mViewFlipper.getDisplayedChild() == 0)
                    break;

                mViewFlipper.setInAnimation(this, R.anim.in_from_left);
                mViewFlipper.setOutAnimation(this, R.anim.out_to_right);

                mViewFlipper.showPrevious();
            }

            // right to left swipe
            if (lastX > currentX)
            {
                if (mViewFlipper.getDisplayedChild() == mViewFlipper.getChildCount() - 1)
                    break;

                mViewFlipper.setInAnimation(this, R.anim.in_from_right);
                mViewFlipper.setOutAnimation(this, R.anim.out_to_left);

                mViewFlipper.showNext();
            }

            break;
        }
    }

    return false;
}

When I debug the code, I don't see any differences between when the animation is working and when it isn't. Also, I see this behavior on an actual device and the emulator. What did I miss? I can post the animation xml files and the view xml, if they are needed.

EDIT:

The only way I am able to get this to work as expected is to set the following in the onCreate method:

   mViewFlipper.setInAnimation(this, R.anim.in_from_right);
    mViewFlipper.setOutAnimation(this, R.anim.out_to_left);
    mViewFlipper.setFlipInterval(10000);
    mViewFlipper.startFlipping();

I then call stopFlipping() on the first swipe. The interesting thing to me is that the animation works on the first swipe with these changes, even if the first auto-flip hasn't occurred. However, if I simply set the animation in the onCreate method without calling the startFlipping() method, it still doesn't have the animation on the first swipe. Can someone offer an explanation as to why this behavior occurs?

Induna answered 29/6, 2015 at 12:34 Comment(3)
Just to check, looking at the source code of the ViewFlipper class, when you call ViewFlipper.showNext(), the ViewAnimator.showOnly(int position) method is called. This is the validation done inside thats method: final boolean animate = (!mFirstTime || mAnimateFirstTime); showOnly(childIndex, animate);. So, what could be happening is that the animation is simply ignored on the first flip. I'm not 100% about this but you can check it by adding mViewFlipper.setAnimateFirstView(true) in the onCreate (instead of the lines you have in the edit)Chimene
I'll give it a try when I get a chance.Induna
@Chimene That worked. Post it as an answer and I'll accept it. Thanks!Induna
C
1

Looking through the ViewFlipper class's source code, the ViewFlipper.showNext() internally calls the ViewAnimator.showOnly(int position) method.

This is the validation performed inside that method:

   void showOnly(int childIndex) {
        final boolean animate = (!mFirstTime || mAnimateFirstTime);
        showOnly(childIndex, animate);
   }

So, in order to achieve what you want, you'll need to tell the ViewFlipper to animate the first flip inside your Activity.onCreate:

    @Override
    void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.my_activity);
        mViewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
        mViewFlipper.setAnimateFirstView(true);
   }

NOTE:

I was able to achieve this without calling mViewFlipper.setAnimateFirstView(true) using API level 22. But it doesn't seem to work the same on previous versions.

Chimene answered 9/7, 2015 at 14:47 Comment(0)
R
2

At first, you dont have true algorythm of your onTouchEvent. Now you get something like inversion with incorrect animation order setting.

Try to use my onTouchEvent, this is work for me like a charm:

   public boolean onTouchEvent(MotionEvent touchevent)
    {
        switch (touchevent.getAction())
        {
            // when user first touches the screen to swap
            case MotionEvent.ACTION_DOWN:
            {
                lastX = touchevent.getX();
                break;
            }
            case MotionEvent.ACTION_UP:
            {
                float currentX = touchevent.getX();

                // if left to right swipe on screen
                if (lastX < currentX)
                {
                    // If no more View/Child to flip
                    if (viewFlipper.getDisplayedChild() == 0)
                        break;

                    // set the required Animation type to ViewFlipper
                    // The Next screen will come in form Left and current Screen will go OUT from Right
                    viewFlipper.setInAnimation(this, R.anim.in_from_left);
                    viewFlipper.setOutAnimation(this, R.anim.out_to_right);
                    // Show the next Screen
                    viewFlipper.showNext();
                }

                // if right to left swipe on screen
                if (lastX > currentX)
                {
                    if (viewFlipper.getDisplayedChild() == 1)
                        break;
                    // set the required Animation type to ViewFlipper
                    // The Next screen will come in form Right and current Screen will go OUT from Left
                    viewFlipper.setInAnimation(this, R.anim.in_from_right);
                    viewFlipper.setOutAnimation(this, R.anim.out_to_left);
                    // Show The Previous Screen
                    viewFlipper.showPrevious();
                }
                break;
            }
        }
        return true;
    }
Rexford answered 1/7, 2015 at 22:26 Comment(4)
I made the changes, but the result is the same. On the first swipe, there is no animation. Every swipe thereafter, the animation works as expected.Induna
I don't think so, since the animation works, just not on the first swipe. See my edit.Induna
Try it on another phone, may be there is some issues with animation on your phone ?Ragamuffin
I've tried an actual device and the emulator. Both exhibit the same behavior.Induna
C
1

Looking through the ViewFlipper class's source code, the ViewFlipper.showNext() internally calls the ViewAnimator.showOnly(int position) method.

This is the validation performed inside that method:

   void showOnly(int childIndex) {
        final boolean animate = (!mFirstTime || mAnimateFirstTime);
        showOnly(childIndex, animate);
   }

So, in order to achieve what you want, you'll need to tell the ViewFlipper to animate the first flip inside your Activity.onCreate:

    @Override
    void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.my_activity);
        mViewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
        mViewFlipper.setAnimateFirstView(true);
   }

NOTE:

I was able to achieve this without calling mViewFlipper.setAnimateFirstView(true) using API level 22. But it doesn't seem to work the same on previous versions.

Chimene answered 9/7, 2015 at 14:47 Comment(0)
E
0
Try to use this gesture for swipe with animation just get animation swipe left to right and right to left and put inside this:

   final GestureDetector gesture = new GestureDetector(getActivity(),
                new GestureDetector.SimpleOnGestureListener() {

                    @Override
                    public boolean onDown(MotionEvent e) {
                        return true;
                    }

                    @Override
                    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                            float velocityY) {
                        Log.i("null", "onFling has been called!");
                        final int SWIPE_MIN_DISTANCE = 80;
                        final int SWIPE_MAX_OFF_PATH = 150;
                        final int SWIPE_THRESHOLD_VELOCITY = 100;
                        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) {
                                try {

                                  //your swipe code 
                                } catch (Exception e) {
                                    n = -1;
                                }

                            } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                                try {

//your swipe code 
                         } catch (Exception e) {

                                }

                            }
                        } catch (Exception e) {
                        }
                        return super.onFling(e1, e2, velocityX, velocityY);
                    }
                });
        yourFullRelativeLayout.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return gesture.onTouchEvent(event);
            }
        });
        yourView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return gesture.onTouchEvent(event);
            }
        });
Eyeleen answered 7/7, 2015 at 5:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.