Monday, December 11, 2017

Android ViewPager detect swipe beyond bounds and go to next activity.

Date : 11 / 12 / 2017

Today my client wants me to automatically open the next view(next activity) when the user comes to the last page and swipe left. I have searched and found good solutions on SO but they seems to be complex than I thought. So I looked and played with some methods in ViewPager and created an easy solution.

I used  OnPageChangeListener in  ViewPager  class. Here we have 3 methods.


  1. void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
  2. void onPageSelected(int position);
  3. void onPageScrollStateChanged(int state);
We are going to use onPageSelected() and onPageScrollStateChanged() for our purpose.

It is important to know what are the states in  onPageScrollStateChanged() and their sequence of execution.There are 3 states as SCROLL_STATE_IDLE, SCROLL_STATE_DRAGGING and SCROLL_STATE_SETTLING.

This is extracted from android documentation.
/** * Called when the scroll state changes. Useful for discovering when the user 
* begins dragging, when the pager is automatically settling to the current page, 
* or when it is fully stopped/idle. 
* * @param state The new scroll state. 
* @see ViewPager#SCROLL_STATE_IDLE 
* @see ViewPager#SCROLL_STATE_DRAGGING 
* @see ViewPager#SCROLL_STATE_SETTLING */
void onPageScrollStateChanged(int state);

Here is the execution order.
Scroll_state_dragging --> Scroll_state_settling --> onPageSelected() --> Scroll_state_idle

(note: scroll_state_dragging occur multiple times.)

The idea is keeping a flag inside onPageSelected() to record current page number. Then if user in the last page and swipe left scroll_state_dragging called and launch the next view.

private int pagePosition; // keep a class variable
private int[] layouts= new int[]{
        R.layout.welcome_slide1,
        R.layout.welcome_slide2,
        R.layout.welcome_slide3}; 
ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {

    @Override   
    public void onPageSelected(int position) {
        addBottomDots(position);
        pagePosition = position;
    }

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

    @Override   
    public void onPageScrollStateChanged(int state) {
        if (state == ViewPager.SCROLL_STATE_DRAGGING) {
            if (pagePosition == layouts.length - 1) {
                launchHomeScreen();
            }
        }
    }
};
private void launchHomeScreen() {
    startActivity(new Intent(IntroductionActivity.this, MainDockerActivity.class));
    finish();
}

Easy as that. Here is my full code implementation. (filter for what you want.)

 package com.YOURAPP.android.app;  
 import android.content.Context;  
 import android.content.Intent;  
 import android.graphics.Color;  
 import android.graphics.Typeface;  
 import android.os.Build;  
 import android.os.Bundle;  
 import android.support.v4.content.res.ResourcesCompat;  
 import android.support.v4.view.PagerAdapter;  
 import android.support.v4.view.ViewPager;  
 import android.text.Html;  
 import android.view.LayoutInflater;  
 import android.view.View;  
 import android.view.ViewGroup;  
 import android.view.Window;  
 import android.view.WindowManager;  
 import android.widget.Button;  
 import android.widget.LinearLayout;  
 import android.widget.TextView;  
 import butterknife.BindView;  
 public class IntroductionActivity extends BaseActivity {  
   @BindView(R.id.view_pager_intro)  
   ViewPager viewPager;  
   @BindView(R.id.btn_skip)  
   Button btnSkip;  
   private LinearLayout dotsLayout;  
   private int[] layouts;  
   private Typeface typefaceNormal;  
   private Typeface typefaceBold;  
   private int pagePosition;  
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     if (Build.VERSION.SDK_INT >= 21) {  
       getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);  
     }  
     dotsLayout = findViewById(R.id.layoutDots);  
     layouts = new int[]{  
         R.layout.welcome_slide1,  
         R.layout.welcome_slide2,  
         R.layout.welcome_slide3};  
     typefaceNormal = ResourcesCompat.getFont(this, R.font.gill_sans_book);  
     typefaceBold = ResourcesCompat.getFont(this, R.font.gill_sans_bold);  
     addBottomDots(0);  
     // making notification bar transparent  
     changeStatusBarColor();  
     MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter();  
     viewPager.setAdapter(myViewPagerAdapter);  
     viewPager.addOnPageChangeListener(viewPagerPageChangeListener);  
     btnSkip.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View v) {  
         launchHomeScreen();  
       }  
     });  
   }  
   @Override  
   protected int getContentView() {  
     return R.layout.activity_introduction;  
   }  
   private void addBottomDots(int currentPage) {  
     TextView[] dots = new TextView[layouts.length];  
     int[] colorsActive = getResources().getIntArray(R.array.array_dot_active);  
     int[] colorsInactive = getResources().getIntArray(R.array.array_dot_inactive);  
     dotsLayout.removeAllViews();  
     for (int i = 0; i < dots.length; i++) {  
       dots[i] = new TextView(this);  
       dots[i].setText(Html.fromHtml("&#8226;"));  
       dots[i].setTextSize(35);  
       dots[i].setTextColor(colorsInactive[currentPage]);  
       dotsLayout.addView(dots[i]);  
     }  
     if (dots.length > 0)  
       dots[currentPage].setTextColor(colorsActive[currentPage]);  
   }  
   private int getItem(int i) {  
     return viewPager.getCurrentItem() + i;  
   }  
   private void launchHomeScreen() {  
     startActivity(new Intent(IntroductionActivity.this, MainDockerActivity.class));  
     finish();  
   }  
   ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {  
     @Override  
     public void onPageSelected(int position) {  
       addBottomDots(position);  
       pagePosition = position;  
     }  
     @Override  
     public void onPageScrolled(int position, float positionOffset, int arg2) {  
     }  
     @Override  
     public void onPageScrollStateChanged(int state) {  
       if (state == ViewPager.SCROLL_STATE_DRAGGING) {  
         if (pagePosition == layouts.length - 1) {  
           launchHomeScreen();  
         }  
       }  
     }  
   };  
   //Making notification bar transparent  
   private void changeStatusBarColor() {  
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  
       Window window = getWindow();  
       window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);  
       window.setStatusBarColor(Color.TRANSPARENT);  
     }  
   }  
   public class MyViewPagerAdapter extends PagerAdapter {  
     private LayoutInflater layoutInflater;  
     public MyViewPagerAdapter() {  
     }  
     @Override  
     public Object instantiateItem(ViewGroup container, int position) {  
       layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
       View view = layoutInflater.inflate(layouts[position], container, false);  
       TextView mainTitle = view.findViewById(R.id.main_title);  
       TextView introDescription = view.findViewById(R.id.intro_description);  
       mainTitle.setTypeface(typefaceBold);  
       introDescription.setTypeface(typefaceNormal);  
       container.addView(view);  
       return view;  
     }  
     @Override  
     public int getCount() {  
       return layouts.length;  
     }  
     @Override  
     public boolean isViewFromObject(View view, Object obj) {  
       return view.equals(obj);  
     }  
     @Override  
     public void destroyItem(ViewGroup container, int position, Object object) {  
       View view = (View) object;  
       container.removeView(view);  
     }  
   }  
 }  

Hope It will be useful to someone. Happy Coding :-)