Android ViewFlipper and ViewSwitcher with GestureDetector Swipes/Flings

While developing an Android application, most of us will encounter the need to integrate a section in our app where the user can switch between Views. So it should show one view which can be an ImageView or a collection inside LinearLayout, RelativeLayout, etc. at a time that can be swiped/flinged to move to the next or previous item. Think of a slideshow of images or a step-based process like e-commerce checkouts. Basically whenever you want to swipe through a set of related sections but show only one at a time then you can leverage ViewFlipper or ViewSwitcher class widgets that Android provides us. The detection of gestures can be achieved with major use of the MotionEvent class but we’ll make use of GestureDetector for this article.

ViewFlipper

So when we want to flip between two or more views, the ViewFlipper class is what we’d most probably look at. We’ll try to create an ImageView slideshow using it so let’s first define our layout resource at res/layout/activity_gesture.xml:

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:id="@+id/relativeLayout">


    <ViewFlipper
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/viewFlipper"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

    </ViewFlipper>

</RelativeLayout>

Now obviously there are two ways to add our child views into the ViewFlipper:

  • Add them in this layout resource itself.
  • Add them programatically.

We’ll go with the second approach in our example. Before that you might want to get 5-6 odd image resources and put them in res/drawable/ directory. Personally, I downloaded six 400×600 images from LoremPixel and shoved them into the drawable directory. For naming them I used first.png, second.png, third.png and so on.

So the immediate next thing to do is, add the image views to the ViewFlipper programatically like this from the onCreate() method of our Activity:

private ViewFlipper mViewFlipper;
private GestureDetector mGestureDetector;

int[] resources = {
        R.drawable.first,
        R.drawable.second,
        R.drawable.third,
        R.drawable.fourth,
        R.drawable.fifth,
        R.drawable.sixth
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_gesture);

    // Get the ViewFlipper
    mViewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);

    // Add all the images to the ViewFlipper
    for (int i = 0; i < resources.length; i++) {
        ImageView imageView = new ImageView(this);
        imageView.setImageResource(resources[i]);
        mViewFlipper.addView(imageView);
    }
}

Now if you test your app activity in the emulator or a real handset then you’ll just see the first view. If you try to slide your fingers/mouse/pointer over the touch screen then nothing will happen. Hence, next we will integrate gesture detection using the GestureDetector class. For that we’ll first implement our custom gesture detector class as an inner class of our activity.

class CustomGestureDetector extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        // Swipe left (next)
        if (e1.getX() > e2.getX()) {
            mViewFlipper.showNext();
        }

        // Swipe right (previous)
        if (e1.getX() < e2.getX()) {
            mViewFlipper.showPrevious();
        }

        return super.onFling(e1, e2, velocityX, velocityY);
    }
}

Super easy to understand code. If the initial touch X coordinate is more than the final touch X position then it was a left swipe which means the intent was to see the next picture. If it’s just the opposite then showPrevious() needs to be called on the view flipper object.

The final step is to instantiate our custom gesture detector class and then re-route all the touch events to it from our Activity’s onTouchEvent() method. The instantiation code needs to go into our onCreate() method:

CustomGestureDetector customGestureDetector = new CustomGestureDetector();
mGestureDetector = new GestureDetector(this, customGestureDetector);

The onTouchEvent() implementation will be like this:

@Override
public boolean onTouchEvent(MotionEvent event) {
    mGestureDetector.onTouchEvent(event);

    return super.onTouchEvent(event);
}

If you test the code on your device, you’ll notice the flipping between Views work great! Congrats on building your first slideshow with ViewFlipper! But the problem is there’s no animation for the flipping motion which makes the experience really bland. So let’s add a really basic fade in and fade out animation by using a couple of android’s built-in animation resources. All we have to do is add this piece of code in the onCreate() method:

// Set in/out flipping animations
mViewFlipper.setInAnimation(this, android.R.anim.fade_in);
mViewFlipper.setOutAnimation(this, android.R.anim.fade_out);

Wow! Now there’s some interesting transition happening when the images are swiped. So here’s how our entire activity class will be like:

public class GestureActivity extends Activity {

    private ViewFlipper mViewFlipper;
    private GestureDetector mGestureDetector;

    int[] resources = {
            R.drawable.first,
            R.drawable.second,
            R.drawable.third,
            R.drawable.fourth,
            R.drawable.fifth,
            R.drawable.sixth
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gesture);

        // Get the ViewFlipper
        mViewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);

        // Add all the images to the ViewFlipper
        for (int i = 0; i < resources.length; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(resources[i]);
            mViewFlipper.addView(imageView);
        }

        // Set in/out flipping animations
        mViewFlipper.setInAnimation(this, android.R.anim.fade_in);
        mViewFlipper.setOutAnimation(this, android.R.anim.fade_out);

        CustomGestureDetector customGestureDetector = new CustomGestureDetector();
        mGestureDetector = new GestureDetector(this, customGestureDetector);
    }

    class CustomGestureDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            // Swipe left (next)
            if (e1.getX() > e2.getX()) {
                mViewFlipper.showNext();
            }

            // Swipe right (previous)
            if (e1.getX() < e2.getX()) {
                mViewFlipper.showPrevious();
            }

            return super.onFling(e1, e2, velocityX, velocityY);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);

        return super.onTouchEvent(event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.gesture, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Automatically Start Flipping

If you want to auto-start flipping then the `ViewFlipper` API gives us the ability to do so. In the onCreate() method just put this:

mViewFlipper.setAutoStart(true);
mViewFlipper.setFlipInterval(2000); // flip every 2 seconds (2000ms)

Setting setAutoStart() to true will automatically call startFlipping() when the view flipper is attached to the window. setFlipInterval() defines the interval between each flips in milliseconds.

You might want to add a play icon/button that should trigger the slideshow. In that case you just set a click listener on that View that’ll trigger startFlipping() while the stop button will call stopFlipping().

Custom Sliding Flipping Animations

Instead of the built-in android animations we can also write our own animation XML resources and apply that to the transition. Let’s see how to write a simple one where the images will slide in and out of the screen on swipe. We’ll create four animation resources for:

  • Next image to come into screen (left_in.xml) and current image to move out from the left (left_out.xml) on swiping to left.
  • Previous image to come into screen (right_in.xml) and current image to move out from the right (right_out.xml) on swiping to the right.

Code for res/anim/left_in.xml:

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="500"
        android:fromXDelta="100%p"
        android:toXDelta="0" />

    <alpha
        android:duration="500"
        android:fromAlpha="0.1"
        android:toAlpha="1.0" />

</set>

Code for res/anim/left_out.xml:

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="500"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />

    <alpha
        android:duration="500"
        android:fromAlpha="1.0"
        android:toAlpha="0.1" />
</set>

Code for res/anim/right_in.xml:

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="500"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />

    <alpha
        android:duration="500"
        android:fromAlpha="0.1"
        android:toAlpha="1.0" />

</set>

Code for res/anim/right_out.xml:

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="500"
        android:fromXDelta="0"
        android:toXDelta="100%p" />

    <alpha
        android:duration="500"
        android:fromAlpha="1.0"
        android:toAlpha="0.1" />

</set>

Now in the Activity class’s onCreate() method remove the setInAnimation() and setOutAnimation() method calls on the view flipper object. We’ll need them in the if blocks of our custom gesture detector class’s onFling() method. Here’s how our new custom gesture detector will look like after setting the new animation resources:

class CustomGestureDetector extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        // Swipe left (next)
        if (e1.getX() > e2.getX()) {
            mViewFlipper.setInAnimation(GestureActivity.this, R.anim.left_in);
            mViewFlipper.setOutAnimation(GestureActivity.this, R.anim.left_out);

            mViewFlipper.showNext();
        }

        // Swipe right (previous)
        if (e1.getX() < e2.getX()) {
            mViewFlipper.setInAnimation(GestureActivity.this, R.anim.right_in);
            mViewFlipper.setOutAnimation(GestureActivity.this, R.anim.right_out);

            mViewFlipper.showPrevious();
        }

        return super.onFling(e1, e2, velocityX, velocityY);
    }
}

Test it out in your device or emulator. You’ll enjoy some nice sliding effects while flipping over images in the slideshow.

Instead of using gestures to switch between views, you can also have buttons with click listeners that’d fire the mViewFlipper.showNext() and mViewFlipper.showPrevious() actions.

ViewSwitcher

By now if you’ve properly understood ViewFlipper then ViewSwitcher will be a piece of cake for you. Just like ViewFlipper, ViewSwitcher is also a ViewAnimator (they are sub classes of ViewAnimator) that can hold only two child views (only significant difference with view flipper feature-wise) and show one at a time. We can add child views to it just like we did with our ViewFlipper or use its factory to create the views.

If we add Views like we did in the previous case:

// Get the ViewFlipper
mViewSwitcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);

// Add all the images to the ViewFlipper
for (int i = 0; i < resources.length; i++) {
    ImageView imageView = new ImageView(this);
    imageView.setImageResource(resources[i]);
    mViewSwitcher.addView(imageView);
}

This will work fine as long as resources has only 2 items, else it’ll throw an exception with the message java.lang.IllegalStateException: Can't add more than 2 views to a ViewSwitcher.

Instead of calling addView() twice we can also call setFactory() on the ViewSwitcher object to set the factory that’d create the two views between which the user will switch (although I’d just prefer calling addView() two times).

mViewSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
    @Override
    public View makeView() {
        ImageView imageView = new ImageView(GestureActivity.this);
        imageView.setImageResource(resources[0]);

        // Log.d(TAG, "setFactory#makeView");

        return imageView;
    }
});

The makeView() method will get called twice to generate two views. In this case it’s using the same resource as the image so we’ll have to set some condition (maybe based on mViewSwitcher.getChildCount()) to make sure that the second time some other resource is selected for the second view.

Here’s how your Activity making use of ViewSwitcher would look like (pretty much similar to the previous example using ViewFlipper):

public class GestureActivity extends Activity {

    // private ViewFlipper mViewFlipper;
    private ViewSwitcher mViewSwitcher;
    private GestureDetector mGestureDetector;

    int[] resources = {
            R.drawable.first,
            R.drawable.second/*,
            R.drawable.third,
            R.drawable.fourth,
            R.drawable.fifth,
            R.drawable.sixth*/
    };

    private String TAG = GestureActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gesture);

        // Get the ViewFlipper
        mViewSwitcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);

        /*mViewSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                ImageView imageView = new ImageView(GestureActivity.this);
                imageView.setImageResource(resources[0]);

                Log.d(TAG, "setFactory#makeView");

                return imageView;
            }
        });*/

        // Add all the images to the ViewFlipper
        for (int i = 0; i < resources.length; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(resources[i]);
            mViewSwitcher.addView(imageView);
        }

        // Set in/out flipping animations
        //mViewFlipper.setInAnimation(this, android.R.anim.fade_in);
        //mViewFlipper.setOutAnimation(this, android.R.anim.fadeout);

        CustomGestureDetector customGestureDetector = new CustomGestureDetector();
        mGestureDetector = new GestureDetector(this, customGestureDetector);
    }

    class CustomGestureDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            // Swipe left (next)
            if (e1.getX() > e2.getX()) {
                mViewSwitcher.setInAnimation(GestureActivity.this, R.anim.left_in);
                mViewSwitcher.setOutAnimation(GestureActivity.this, R.anim.left_out);

                mViewSwitcher.showNext();
            }

            // Swipe right (previous)
            if (e1.getX() < e2.getX()) {
                mViewSwitcher.setInAnimation(GestureActivity.this, R.anim.right_in);
                mViewSwitcher.setOutAnimation(GestureActivity.this, R.anim.right_out);

                mViewSwitcher.showPrevious();
            }

            /*mViewSwitcher.getInAnimation().setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    Log.d(TAG, "Animation End");
                    Log.d(TAG, "Child Count: " + mViewSwitcher.getChildCount());
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });*/

            return super.onFling(e1, e2, velocityX, velocityY);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);

        return super.onTouchEvent(event);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.gesture, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Off the bat, one use of ViewSwitcher that I can think of is cases when you’ll need to have login and registration forms or maybe after the login submit button is clicked, the second view can show a loader or some confirmation message.

Differences Between ViewFlipper and ViewSwitcher

I came across these two classes when I really needed to transform one view to another for a specific requirement in my app which is similar to an image slideshow. Now based on the knowledge we’ve since we covered both of them in fair amount of details, the only difference between these two classes is that, ViewSwitcher supports only two views while ViewFlipper can have multiple. Also ViewSwitcher can source its views from a factory which has to be set via setFactory().

In most cases we’ll probably just want to use ViewFlipper over the other one.

Conclusion

These widgets are pretty nifty when a specific requirement entails moving between/among various Views. Although for my requirement I ended up using ViewPager because I really wanted its style of sliding transition where once the current image is pulled to the left the next one is also drawn along with it. Until a certain threshold if you release the image (or the View) then it’ll get back to its original state and the next View will move off the screen from the right edge.

If you’ve any questions regarding these view animators then feel free to discuss in the comments section.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

18 thoughts on “Android ViewFlipper and ViewSwitcher with GestureDetector Swipes/Flings”

  1. Hi,
    Thanks for the details. As in ViewFlipper we can show one view at a time. But is it possible to show multiple childs to that layout. Like In single viewflipper , want to show the listview and the listview will have its childs,.. Finally, for viewFlipper view,i want set the adapter for multiple childs. Please reply whether it is possible or not

    Thanks..

    1. Oh yes, definitely! A ViewFlipper for instance can contain multiple ViewGroups (RelativeLayout, LinearLayout, FrameLayout, etc.) that in turn can contain other childs (Views or ViewGroups like TextView, EditText, ImageView, ListView, GridView, etc.).

      So basically what you want is a ViewFlipper with multiple Relative/LinearLayouts (as each page) that in turn contains a ListView with items in it. Binding a ListView to its Adapter to pipe in data is pretty much same as usual, nothing special you’ll need to do in this case. Here’s my article on ListView – http://codetheory.in/understanding-android-lists/ – if you need further help with it.

  2. Sir I want a help from you in android. Suppose I have multiple images in drawable folder (8 images) and I want to show all these images in a imageView one after another with left to right flip effect repeatedly (img[0], img[1], …, img[8], img[0], img[1], …). How can i do this ?

    1. Good question Sritam. I’m not exactly sure on how to do this right now. But here’s something I’ve thought of that might work but seems like an ugly solution.

      Have 10 resources in your array where the 1st one is the 8th image and 10th one is the 1st image. So basically first is last image and last item is first image.

      As soon as the user/slideshow moves to the 10th position use setCurrentItem() to move to the second position which is your first image. Remember 2nd and 10th position have the first image whereas 1st and 9th have the last (8th image).

      Here (being on the 2nd pos, 1st image) if the user tries to go back to the previous image then he’ll land up on the 1st position which is the last image. Right then move him to the second last position (9th) which is your last image from where he can go to the previous position (8th pos, 7th image) or next (10th pos, 1st image). Going to the next one will actually switch to the 2nd position (1st image) automatically using the same method.

      You may set false to disable smooth scrolling while jumping. I haven’t tried this method but hopefully should work.

  3. hiiii
    As i am new to android. can i get your help to create a project.
    which i need is viewflipper with selected images from gallery.
    (Which means we can select images from gallery as 3 to 4 and those images to be placed in viewflipper. so, if project will be looking soooo coooollll….)

    1. This can be done actually. Check out the Media Store provider. You can fetch all your multimedia files in a GridView. Once that’s done apply multi selection logic and on a button press take all the Image URIs and show up in the ViewFlipper. Could use the setImageUri() or setImageBitmap() methods on ImageViews to set the image resource.

      1. hiii,
        i am trying what had u said in the last reply to my comment.
        i have done until gallery images to gridview and multiple image loader code.
        but i am not getting any idea of getting multiple images url to view flipper.
        can u plz suggest me in the last part.

  4. Hi,

    i’m trying to use your code but as part of the first possibility : having viewFlipper with relativeLayout already defined inside (into xml)…

    but i can’t do it … when i try to find the viewFlipper with findViewById i got a null value …

    my code :
    setContentView(R.layout.activity_alarm_list);
    viewFlip = (ViewFlipper) findViewById(R.id.viewFlipper01);
    if(viewFlip == null) {
    Log.d(“null”,”is null”);
    }

    any idea why ?

  5. Hi,
    Is it possible to add Gallery Images to ViewFlipper. I searched but did not get any information regarding this.
    Thanks.

    1. I do plan to write an article on that in near future but do check my response to Venkata Tarun. That contains the solution to your problem, you’ll just have to do a bit of research work. It should be fairly easy!

      Basically you use the Media Store provider to fetch your gallery images and shove them into the ViewFlipper.

  6. Hi Rishabh,
    Thanks for nice tutorial but I have one question. I implemented the view flipper. It’s working fine but the scroll is not faster. It’s working very slow on real device and on emulator it’s working smooth. Can you please suggest the solution???

  7. Hi,
    I have tried to incorporate next and previous buttons to flip the images. I am using onClickListener for the buttons. Functionality of the buttons are working properly, but the animations is not proper. Please help!

  8. Hii your explaination is simply super : ). I want to implement both auto and manual sliding for viewflipper along with indicators (dots) .
    can YOu plz help me in this (‘.’).

Leave a Reply

Your email address will not be published. Required fields are marked *