Friday 29 November 2013

Create a Fade In/Fade Out Effect With Fragments Within a View Pager

So I am working on my new app, and from the start I wanted it to have a combination of Pager Tabs Strips and View Pager in my app (the kind you see in Play Store app)

What else I thought will be cool is to have a fade in/fade out effect as the fragments in my app are scrolled within the View Pager. I have not seen this being implemented in any other app, so thought I'll explain how I did it.

First, familiarize yourself with what a View Pager is here.

1) Create an adaptor and assign it to your instance of View Pager:

MyAdapter mAdapter = new MyAdapter(getSupportFragmentManager());

final ViewPager mPager = (ViewPager) findViewById(R.id.pager);

mPager.setAdapter(mAdapter);

2) Create an On Page Change Listener for you View Pager instance:

mPager.setOnPageChangeListener(new OnPageChangeListener() {

      @Override  
       public void onPageSelected(int position) {}

      @Override
      public void onPageScrolled(int position, float offset, int arg2) {}

      @Override
       public void onPageScrollStateChanged(int state) {}
}

3) The idea is to reduce or increase the alpha value of each fragments parent layout as you scroll in and out of the fragments. I have three fragments, each with one parent layout:
Fragment 0: achievementLayout
Fragment 1: dbLayout
Fragment 2: adHocLayout

Before you can increase/reduce the alpha levels on these layouts, you need to retrieve your layouts in the onPageScrollStateChanged method. I found it best to get the current page being scrolled in this method itself, using the SCROLL_STATE_DRAGGING event. The page being scrolled is being stored in temp_page. 

@Override
public void onPageScrollStateChanged(int state) {
       //define layouts once
       dbLayout = (RelativeLayout) findViewById(R.id.dbLayout);
       adHocLayout = (RelativeLayout) findViewById(R.id.adHocLayout); 
       achievementLayout = (RelativeLayout) findViewById(R.id.achievementLayout);

       //once dragging starts capture the dragged page
       if(state == ViewPager.SCROLL_STATE_DRAGGING){
              temp_page = mPager.getCurrentItem();
       }
}

4) Now that we have the page being scrolled and the layouts, we can start the fade in fade out. This will happen in the onPageScrolled method. 

@Override
public void onPageScrolled(int position, float pos, int arg2) {
        switch (temp_page){
        
             //Fragment 0 scroll
             case 0:
                  achievementLayout.setAlpha(1-offset);
                  break;

             //Fragment 1 scroll
             case 1:
                   //swiping to higher
                   if(temp_offset<pos){
                           dbLayout.setAlpha(1-pos);
                           adHocLayout.setAlpha(pos);
                  }
                  //swiping to lower
                  else if(temp_offset>pos){
                          dbLayout.setAlpha(pos);
                          achievementLayout.setAlpha(1-pos);
                  }
                 temp_offset = pos;

                 break;

           //Fragment 2 scroll
           case 2:
                 adHocLayout.setAlpha(offset);
                 dbLayout.setAlpha(1-offset);
                 break;
      }
}

Offset value starts from 0 and goes up to 1 when a fragment is scrolled from left to right, and vice versa when scrolled from right to left. Hence alpha is set either directly or by doing a (1-offset). The tricky part here is how to determine if the fragment is being scrolled left to right or right to left in the case of the middle fragment (Fragment 1). To overcome this, I used a temporary variable temp_offset to capture the offset value and compare it to the next offset value, if temp_offset is lower than the next offset, then the fragment is being scrolled from right to left and vice versa. 

There are a few other minor tweaks which you can make to smoothen the scroll and the flickering. But if you've understood the above piece, that is child's play.

Hope this helps.

Till next time.

No comments:

Post a Comment