View Pager With Circular Indicator (without any library)

There are number of libraries available to create circular indicator for view pager. But i think you don't require that all heavy weight libraries. They all filled with so much congested and non used code in it. It may happen you may come across some odd issue with those libs. So to save your time and even with easy to understand code i have written this tutorial. Go through full tutorial and you find how easy it is.

I have created View pager for introduction of the application (Current trend of application start screen almost in all Google apps). But you can use it as per your requirement.

viewpager demo


Steps

Step -1
Create activity (welcome screen) which holds pager to display images and give proper name to it. In this tutorial it is ViewPagerDemo Activity. now put below code inside into xml file (layout file).

activity_viewpager_demo.xml

<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:fitsSystemWindows="true"
    tools:context="com.androprogrammer.tutorials.samples.ViewPagerDemo">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager_introduction"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:listitem="@layout/pager_item" />

    <RelativeLayout
        android:id="@+id/viewPagerIndicator"
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:layout_alignParentBottom="true"
        android:layout_marginTop="5dp"
        android:gravity="center">

        <LinearLayout
            android:id="@+id/viewPagerCountDots"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:orientation="horizontal" />

        <ImageButton
            android:id="@+id/btn_next"
            android:layout_width="42dip"
            android:layout_height="42dip"
            android:layout_alignParentRight="true"
            android:layout_marginRight="15dip"
            android:background="@drawable/btn_round_semitransperant"
            android:src="@mipmap/ic_navigation_arrow_forward" />

        <ImageButton
            android:id="@+id/btn_finish"
            android:layout_width="42dip"
            android:layout_height="42dip"
            android:layout_alignParentRight="true"
            android:layout_marginRight="15dip"
            android:background="@drawable/btn_round_semitransperant"
            android:contentDescription="Let's start"
            android:src="@mipmap/ic_navigation_check"
            android:visibility="gone" />

    </RelativeLayout>

</RelativeLayout>


Step - 2
Above code will show error but don't worry it is for drawable files. so below are drawable files put the code in appropriate file and your layout is set.

pager_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:fitsSystemWindows="true"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:src="@mipmap/abc1"
        android:id="@+id/img_pager_item"
        android:scaleType="fitXY"
        android:adjustViewBounds="true"
        android:clickable="false"/>

</LinearLayout>


drawable/selecteditem_dot.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" android:useLevel="true"
    android:dither="true">

    <size android:height="12dip" android:width="12dip"/>

    <solid android:color="@color/primary"/>
</shape>


drawable/nonselecteditem_dot.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" android:useLevel="true"
    android:dither="true">

    <size android:height="6dip" android:width="6dip"/>

    <solid android:color="@color/activity_bg"/>
</shape>




Step - 3
For View pager, layout part is done. you can find sample images from here. now let's move to code part where i have created circular dots on the basis of data size. So if you have let say 10 images it will create 10 dots with first one as selected by default. put the code in to activity and make changes as per your project implementation.

ViewPagerDemo.java

package com.androprogrammer.tutorials.samples;

import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.androprogrammer.tutorials.R;
import com.androprogrammer.tutorials.activities.Baseactivity;
import com.androprogrammer.tutorials.adapters.ViewPagerAdapter;

public class ViewPagerDemo extends Baseactivity implements ViewPager.OnPageChangeListener, View.OnClickListener{

    protected View view;
    private ImageButton btnNext, btnFinish;
    private ViewPager intro_images;
    private LinearLayout pager_indicator;
    private int dotsCount;
    private ImageView[] dots;
    private ViewPagerAdapter mAdapter;

    private int[] mImageResources = {
            R.mipmap.abc1,
            R.mipmap.abc2,
            R.mipmap.abc3,
            R.mipmap.abc4,
            R.mipmap.abc5
    };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // To make activity full screen.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        super.onCreate(savedInstanceState);

        setReference();

        toolbar.setVisibility(View.GONE);

    }

    @Override
    public void setReference() {
        view = LayoutInflater.from(this).inflate(R.layout.activity_viewpager_demo,container);

        intro_images = (ViewPager) view.findViewById(R.id.pager_introduction);
        btnNext = (ImageButton) view.findViewById(R.id.btn_next);
        btnFinish = (ImageButton) view.findViewById(R.id.btn_finish);

        pager_indicator = (LinearLayout) view.findViewById(R.id.viewPagerCountDots);

        btnNext.setOnClickListener(this);
        btnFinish.setOnClickListener(this);

        mAdapter = new ViewPagerAdapter(ViewPagerDemo.this, mImageResources);
        intro_images.setAdapter(mAdapter);
        intro_images.setCurrentItem(0);
        intro_images.setOnPageChangeListener(this);
        setUiPageViewController();
    }

    private void setUiPageViewController() {

        dotsCount = mAdapter.getCount();
        dots = new ImageView[dotsCount];

        for (int i = 0; i < dotsCount; i++) {
            dots[i] = new ImageView(this);
            dots[i].setImageDrawable(getResources().getDrawable(R.drawable.nonselecteditem_dot));

            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
            );

            params.setMargins(4, 0, 4, 0);

            pager_indicator.addView(dots[i], params);
        }

        dots[0].setImageDrawable(getResources().getDrawable(R.drawable.selecteditem_dot));
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_next:
                intro_images.setCurrentItem((intro_images.getCurrentItem() < dotsCount)
                        ? intro_images.getCurrentItem() + 1 : 0);
                break;

            case R.id.btn_finish:
                finish();
                break;
        }
    }

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

    }

    @Override
    public void onPageSelected(int position) {
        for (int i = 0; i < dotsCount; i++) {
            dots[i].setImageDrawable(getResources().getDrawable(R.drawable.nonselecteditem_dot));
        }

        dots[position].setImageDrawable(getResources().getDrawable(R.drawable.selecteditem_dot));

        if (position + 1 == dotsCount) {
            btnNext.setVisibility(View.GONE);
            btnFinish.setVisibility(View.VISIBLE);
        } else {
            btnNext.setVisibility(View.VISIBLE);
            btnFinish.setVisibility(View.GONE);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
}


This is code for view pager adapter.which fills all images into view pager and display like gallery.
adapters/ViewPagerAdapter.java

package com.androprogrammer.tutorials.adapters;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.androprogrammer.tutorials.R;

/**
 * Created by Wasim on 11-06-2015.
 */
public class ViewPagerAdapter extends PagerAdapter {

    private Context mContext;
    private int[] mResources;

    public ViewPagerAdapter(Context mContext, int[] mResources) {
        this.mContext = mContext;
        this.mResources = mResources;
    }

    @Override
    public int getCount() {
        return mResources.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((LinearLayout) object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View itemView = LayoutInflater.from(mContext).inflate(R.layout.pager_item, container, false);

        ImageView imageView = (ImageView) itemView.findViewById(R.id.img_pager_item);
        imageView.setImageResource(mResources[position]);

        container.addView(itemView);

        return itemView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((LinearLayout) object);
    }
}


That's it from my side. now run the app and see the result. and at the end i am replacing next button with finish button. if you have any query please let me know in below comment box.

Keep coding...

Source code

28 comments :

  1. Great article, thank you for sharing. I have one question, how would you structure the activity flow for first launch.

    Would you set the WelcomeActivity as the launch activity in the manifest file and call launch the MainActivity if the this was already displayed.

    Or would you keep the MainActivity as the launch activity and call the WelcomeActivity from the MainActivity if it is the first load.

    Regards,

    ReplyDelete
    Replies
    1. Thanks Garfield,
      Yes i set welcome screen as launcher activity then when user click on finish i redirect them to main activity.
      and for second time i put one boolean in preference and one the basis of that next time i skip activity.
      if user have already seen welcome screen then directly redirect them to main activity.

      I hope it will be clear to you.

      Delete
    2. Thank you confirms the idea i had in mind. Do check the preference and call finish() before setContentView to prevent the loading of that that activity (or flash of the screen)?

      Thank you

      Delete
    3. Awesome, thank you. I will let you know how it goes.

      Delete
  2. Got it to work :)

    I had to do a few simple things:
    1. Add "setContentView(R.layout. activity_viewpager_demo);" in activity.
    2. Use alternatives for the next and finish button background and source properties.

    Again, thank you for awesome tutorial.

    ReplyDelete
  3. That's good tutorial, thank you for sharing. But I dont know, what is that Baseactivity ? Please help me, thanks

    ReplyDelete
    Replies
    1. Thank you bayu,
      Base activity is my projects main activity where I have implemented some common functions and toolbar implementation. You can find it on github project repo.

      Delete
  4. What is container in ViewPagerDemo.java
    view = LayoutInflater.from(this).inflate(R.layout.activity_main, container);
    it gives me error

    ReplyDelete
    Replies
    1. Hey nasir ,
      Check my project on github it will help you in understanding project structure. B'z container is part of it.

      Delete
  5. Replies
    1. https://github.com/WasimMemon/Myapplications/blob/master/Tutorials/app/src/main/java/com/androprogrammer/tutorials/samples/ViewPagerDemo.java

      Check this out.

      Delete
  6. Thanks Wasim, it was really helpful! Although setOnPageChangedListener is deprecated I used addPageChangedListener instead

    ReplyDelete
  7. whwre is the exact location of container error i will get to resolve plzz tell me wasim

    ReplyDelete
    Replies
    1. Check my project on github it will help you in understanding project structure. B'z container is part of it.

      https://github.com/WasimMemon/Myapplications/tree/master/Tutorials

      Delete
  8. hi,
    in your example, at time only one view is loaded? i mean in circlepageindicatory library, i saw at a time two views are loaded in memory

    ReplyDelete
    Replies
    1. Hi Deepika,
      As you can see i have used view pager and it loads 1 view default at a time of initialization so i think it works same in this also. You can use ViewPager.setOffscreenPageLimit(1) to change if you want.

      Delete
  9. Replies
    1. Its my whole project setup for combining all tutorials in one app.
      Why you have problem with it ?

      Delete
  10. I don't understand what is "container". plz tell me how can i find it ??

    ReplyDelete
    Replies
    1. You can get full code from github and can see how it works and why it is used.

      Delete
  11. I am getting the linearLayout but dots are not visible, why?

    ReplyDelete
  12. Hi, seems awesome stuff! but I can please get a stuff to supply this code line android:background="@drawable/btn_round_semitransperant"

    Regards,
    Gus

    ReplyDelete
  13. is Container a fragment ?? I didn't find it on github link

    ReplyDelete
  14. Really useful article. Thanks for sharing.

    ReplyDelete