Android Post Installation Wizard Using ViewPager

In many applications we download from Google Play Store, they show user wizard sort of walkthrough or asking user to accept license and signup etc for the first time after installation. User is shown current page on screen with strip of circled at bottom highlighted for current page. We will create an Android Application Post Installation Wizard Using ViewPager and add functionality of page indicator using circle strip at the bottom.

android.support.v4.view.ViewPager allows the user to flip left and right through pages of data. We need to set adapter for views to be shown as pages. We will use FragmentPagerAdapter for our ViewPager which will have Fragment as its data item. As soon as Page of ViewPager is changed, we will update page indicator.

Sample Android Application with ViewPagerIndicator

 

[su_button url=”https://github.com/androidsrc/ViewPagerIndicator” target=”blank” style=”stroked” background=”#51d461″ color=”#ffffff” size=”6″ center=”yes” radius=”0″ icon=”icon: arrow-circle-o-down”]Download Complete Source Code[/su_button]

 

[su_youtube url=”https://www.youtube.com/watch?v=nX0l6MVdEuw”]

 

In this tutorial, I have not covered sign in with Facebook and Google+. If interested, you would like to check our posts for social login integration.

Facebook login in Android apps – Using latest SDK

Integrating Google Plus Sign In into your Android Application

1. Create a new Android Application Project with com.androidsrc.viewpagerindicator as package name.

2. Preparing Application Manifest File

I have set theme as no title bar and fullscreen for Wizard. If you don’t want title war to appear, set android:theme attribute for your wizard activity as @android:style/Theme.NoTitleBar.Fullscreen.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.androidsrc.viewpagerindicator"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

3. Create shape drawable for background of Page Indicator

Create a new file /res/drawble/indicator_bg.xml. Define shape as oval with solid white color.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >
	<solid android:color="@android:color/white"/>

</shape>

4. Preparing Layout Files

Our main activity layout will have FrameLayout as parent view so that we can show Page Indicators on top of ViewPager. In my sample, I have used four pages in ViewPager. For this I have used four different View’s wrapped in LinearLayout with horizontal orientation as parent.

/res/layout/activity_main.xml will be as below after including these views.

<FrameLayout 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"
    tools:context="com.androidsrc.viewpagerindicator.MainActivity" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

    <LinearLayout
        android:layout_margin="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_gravity="bottom"
        android:orientation="horizontal" >

        <View
            android:id="@+id/indicator1"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_margin="2dp"
            android:background="@drawable/indicator_bg" />

        <View
            android:id="@+id/indicator2"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_margin="2dp"
            android:background="@drawable/indicator_bg" />

        <View
            android:id="@+id/indicator3"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_margin="2dp"
            android:background="@drawable/indicator_bg" />

        <View
            android:id="@+id/indicator4"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_margin="2dp"
            android:background="@drawable/indicator_bg" />
    </LinearLayout>

</FrameLayout>

Layout for Page 1 incorporates ImageView and TextView. Create file /res/layout/page1.xml.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#008000"
    android:gravity="center" >

    <ImageView
        android:id="@+id/icon_androidsrc"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/camera" />

    <TextView
        style="?android:attr/textAppearanceLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/icon_androidsrc"
        android:layout_margin="20dp"
        android:text="Camera Plus"
        android:textColor="@android:color/white"
        android:textSize="30dp"
        android:textStyle="bold" />

</RelativeLayout>

Similarly create layout files for other three pages as per your design requirements. I have named them as page2.xml, page3.xml and page4.xml. If you want to keep same, you can get source for these layouts by downloading complete application source code above.

5. Preparing Source Files

Create a new class WizardFragment.java which will extend Fragment. We will pass page number to constructor in order to inflate corresponding layout in onCreateView().

package com.androidsrc.viewpagerindicator;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class WizardFragment extends Fragment {

	int wizard_page_position;

	public WizardFragment(int position) {
		this.wizard_page_position = position;
	}

	@Override
	public View onCreateView(LayoutInflater inflater,
			@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
		int layout_id = R.layout.page1;
		switch (wizard_page_position) {
		case 0:
			layout_id = R.layout.page1;
			break;

		case 1:
			layout_id = R.layout.page2;
			break;

		case 2:
			layout_id = R.layout.page3;
			break;

		case 3:
			layout_id = R.layout.page4;
			break;
		}

		return inflater.inflate(layout_id, container, false);
	}
}

Your MainActivity.java should extend FragmentActivity in order to use getSupportFragmentManager() from Support Library. Define a local class ViewPageAdapter which extends FragmentPagerAdapter. It will return new instance of WizardFragment for that item position.

	private class ViewPagerAdapter extends FragmentPagerAdapter {

		private int WIZARD_PAGES_COUNT = 4;

		public ViewPagerAdapter(FragmentManager fm) {
			super(fm);
		}

		@Override
		public Fragment getItem(int position) {
			return new WizardFragment(position);
		}

		@Override
		public int getCount() {
			return WIZARD_PAGES_COUNT;
		}

	}

Define a local class WizardPageChangeListener which will implement OnPageChangeListener. From onPageSelected, we will update page indicators.

	private class WizardPageChangeListener implements OnPageChangeListener {

		@Override
		public void onPageScrollStateChanged(int position) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onPageScrolled(int position, float positionOffset,
				int positionOffsetPixels) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onPageSelected(int position) {
			updateIndicators(position);
		}

	}

Override onBackPressed() to handle back key events for navigating back to previous pages in ViewPager.

@Override
	public void onBackPressed() {
		if (viewPager.getCurrentItem() == 0) {
			// If the user is currently looking at the first step, allow the
			// system to handle the
			// Back button. This calls finish() on this activity and pops the
			// back stack.
			super.onBackPressed();
		} else {
			// Otherwise, select the previous step.
			viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
		}
	}

For updating Page Indicator Views, update on change of page. Set current page indicator width and height relatively larger than other views.

	public void updateIndicators(int position) {
		DisplayMetrics metrics = getResources().getDisplayMetrics();
		int resizeValue = (int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, 25, metrics);
		int defaultValue = (int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, 15, metrics);
		switch (position) {
		case 0:
			indicator1.getLayoutParams().height = resizeValue;
			indicator1.getLayoutParams().width = resizeValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = defaultValue;
			indicator2.getLayoutParams().width = defaultValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = defaultValue;
			indicator3.getLayoutParams().width = defaultValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = defaultValue;
			indicator4.getLayoutParams().width = defaultValue;
			indicator4.requestLayout();

			break;

		case 1:
			indicator1.getLayoutParams().height = defaultValue;
			indicator1.getLayoutParams().width = defaultValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = resizeValue;
			indicator2.getLayoutParams().width = resizeValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = defaultValue;
			indicator3.getLayoutParams().width = defaultValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = defaultValue;
			indicator4.getLayoutParams().width = defaultValue;
			indicator4.requestLayout();
			break;

		case 2:
			indicator1.getLayoutParams().height = defaultValue;
			indicator1.getLayoutParams().width = defaultValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = defaultValue;
			indicator2.getLayoutParams().width = defaultValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = resizeValue;
			indicator3.getLayoutParams().width = resizeValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = defaultValue;
			indicator4.getLayoutParams().width = defaultValue;
			indicator4.requestLayout();
			break;

		case 3:
			indicator1.getLayoutParams().height = defaultValue;
			indicator1.getLayoutParams().width = defaultValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = defaultValue;
			indicator2.getLayoutParams().width = defaultValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = defaultValue;
			indicator3.getLayoutParams().width = defaultValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = resizeValue;
			indicator4.getLayoutParams().width = resizeValue;
			indicator4.requestLayout();
			break;
		}

	}

Final complete code for MainActivity.java after incorporating above changes will be as below.

package com.androidsrc.viewpagerindicator;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;

public class MainActivity extends FragmentActivity {

	private ViewPager viewPager;
	private View indicator1;
	private View indicator2;
	private View indicator3;
	private View indicator4;

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

		indicator1 = (View) findViewById(R.id.indicator1);
		indicator2 = (View) findViewById(R.id.indicator2);
		indicator3 = (View) findViewById(R.id.indicator3);
		indicator4 = (View) findViewById(R.id.indicator4);

		viewPager = (ViewPager) findViewById(R.id.viewPager);
		viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
		viewPager.setOnPageChangeListener(new WizardPageChangeListener());
		updateIndicators(0);
	}

	@Override
	public void onBackPressed() {
		if (viewPager.getCurrentItem() == 0) {
			// If the user is currently looking at the first step, allow the
			// system to handle the
			// Back button. This calls finish() on this activity and pops the
			// back stack.
			super.onBackPressed();
		} else {
			// Otherwise, select the previous step.
			viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
		}
	}

	private class ViewPagerAdapter extends FragmentPagerAdapter {

		private int WIZARD_PAGES_COUNT = 4;

		public ViewPagerAdapter(FragmentManager fm) {
			super(fm);
		}

		@Override
		public Fragment getItem(int position) {
			return new WizardFragment(position);
		}

		@Override
		public int getCount() {
			return WIZARD_PAGES_COUNT;
		}

	}

	private class WizardPageChangeListener implements OnPageChangeListener {

		@Override
		public void onPageScrollStateChanged(int position) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onPageScrolled(int position, float positionOffset,
				int positionOffsetPixels) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onPageSelected(int position) {
			updateIndicators(position);
		}

	}

	public void updateIndicators(int position) {
		DisplayMetrics metrics = getResources().getDisplayMetrics();
		int resizeValue = (int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, 25, metrics);
		int defaultValue = (int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, 15, metrics);
		switch (position) {
		case 0:
			indicator1.getLayoutParams().height = resizeValue;
			indicator1.getLayoutParams().width = resizeValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = defaultValue;
			indicator2.getLayoutParams().width = defaultValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = defaultValue;
			indicator3.getLayoutParams().width = defaultValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = defaultValue;
			indicator4.getLayoutParams().width = defaultValue;
			indicator4.requestLayout();

			break;

		case 1:
			indicator1.getLayoutParams().height = defaultValue;
			indicator1.getLayoutParams().width = defaultValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = resizeValue;
			indicator2.getLayoutParams().width = resizeValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = defaultValue;
			indicator3.getLayoutParams().width = defaultValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = defaultValue;
			indicator4.getLayoutParams().width = defaultValue;
			indicator4.requestLayout();
			break;

		case 2:
			indicator1.getLayoutParams().height = defaultValue;
			indicator1.getLayoutParams().width = defaultValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = defaultValue;
			indicator2.getLayoutParams().width = defaultValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = resizeValue;
			indicator3.getLayoutParams().width = resizeValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = defaultValue;
			indicator4.getLayoutParams().width = defaultValue;
			indicator4.requestLayout();
			break;

		case 3:
			indicator1.getLayoutParams().height = defaultValue;
			indicator1.getLayoutParams().width = defaultValue;
			indicator1.requestLayout();

			indicator2.getLayoutParams().height = defaultValue;
			indicator2.getLayoutParams().width = defaultValue;
			indicator2.requestLayout();

			indicator3.getLayoutParams().height = defaultValue;
			indicator3.getLayoutParams().width = defaultValue;
			indicator3.requestLayout();

			indicator4.getLayoutParams().height = resizeValue;
			indicator4.getLayoutParams().width = resizeValue;
			indicator4.requestLayout();
			break;
		}

	}
}

You may also like...

6 Responses

  1. Jose Luis Crisostomo Sanchez says:

    Hello, I have a question, I would like to use your source but when I tried to call an activity and i Failed, so could you explain me how could I do this? Regards

    • AndroidSRC . says:

      Please share the logs so that we can find the problem.

      • Jose Luis Crisostomo Sanchez says:

        Thanks for your reply, and I’m a newbie in android development so I cannot understand where I have to put my intent to call the other activity, so Into my log file just say “could’nt to find inicio() ‘ and Inicio() is my class to catch when the user push the “let’s go button”

        page 4 .xml

        • AndroidSRC . says:

          just put this function in Activity sub class in which you have inflated that layout. It will go like this.
          public void inicio(View v){
          //perform action here
          }

  2. tushar says:

    my WIZARD_PAGES_COUNT page goes in both case 1 and 2 at same time please help

  3. tushar says:

    03-04 17:47:01.925 13285-13285/com.example.aam.firstscreen D/abhi: wizard_page_position in method fragment::0

    03-04 17:47:01.935 13285-13285/com.example.aam.firstscreen D/abhi: wizard_page_position in method fragment::1

Leave a Reply

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