Skip to content

Instantly share code, notes, and snippets.

@vxhviet
Last active July 11, 2016 02:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vxhviet/ac67eda8ebbe8803ebd09e373932820f to your computer and use it in GitHub Desktop.
Save vxhviet/ac67eda8ebbe8803ebd09e373932820f to your computer and use it in GitHub Desktop.
Parallax ViewPager tutorial

Source: GitHub

Answer: Demo Tutorial screen that use ViewPager with parallax effect:

Go to the github link and add the dependency then create:

TutorialActivity.java:

public class TutorialActivity extends FragmentActivity {

    private ViewPager mPager;
    private TutorialParallaxAdapter mAdapter;
    private CircleIndicatorPager mIndicator;
    private Button mImageView;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_tutorial_parallax);

        mPager = (ViewPager) findViewById(R.id.tutorial_viewPager);
        mPager.setBackgroundColor(0xFF000000);

        ParallaxPagerTransformer pt = new ParallaxPagerTransformer((R.id.tutorial_image));
        pt.setBorder(20);
        pt.setSpeed(0.8f);
        mPager.setPageTransformer(false, pt);

        mAdapter = new TutorialParallaxAdapter(getSupportFragmentManager());
        mAdapter.setPager(mPager); //only for this transformer

        Bundle page1 = new Bundle();
        page1.putInt("image", R.drawable.page1_background);
        page1.putInt("imageLogo", R.drawable.page1_logo);
        page1.putInt("imageText", R.drawable.page1_text);
        TutorialParallaxFragment page1Fragment = new TutorialParallaxFragment();
        page1Fragment.setArguments(page1);

        Bundle page2 = new Bundle();
        page2.putInt("image", R.drawable.page2_background);
        page2.putInt("imageLogo", R.drawable.page2_logo);
        page2.putInt("imageText", R.drawable.page2_text);
        TutorialParallaxFragment page2Fragment = new TutorialParallaxFragment();
        page2Fragment.setArguments(page2);

        Bundle page3 = new Bundle();
        page3.putInt("image", R.drawable.page3_background);
        page3.putInt("imageLogo", R.drawable.page3_logo);
        page3.putInt("imageText", R.drawable.page3_text);
        TutorialParallaxFragment page3Fragment = new TutorialParallaxFragment();
        page3Fragment.setArguments(page3);

        Bundle page4 = new Bundle();
        page4.putInt("image", R.drawable.page4_background);
        page4.putInt("imageLogo", R.drawable.page1_logo);
        page4.putInt("imageText", R.drawable.page4_text);
        TutorialParallaxFragment page4Fragment = new TutorialParallaxFragment();
        page4Fragment.setArguments(page4);

        Bundle page5 = new Bundle();
        page5.putInt("image", R.drawable.page5_background);
        page5.putInt("imageLogo", R.drawable.page5_logo);
        page5.putInt("imageText", R.drawable.page5_text1);
        TutorialParallaxFragment page5Fragment = new TutorialParallaxFragment();
        page5Fragment.setArguments(page5);

        mAdapter.add(page1Fragment);
        mAdapter.add(page2Fragment);
        mAdapter.add(page3Fragment);
        mAdapter.add(page4Fragment);
        mAdapter.add(page5Fragment);
        mPager.setAdapter(mAdapter);

        if (getActionBar() != null) {
            getActionBar().setDisplayHomeAsUpEnabled(true);
            getActionBar().show();
        }

        // setup indicator
        mIndicator = (CircleIndicatorPager) findViewById(R.id.indicator);
        mIndicator.setRadius(10);
        mIndicator.setViewPager(mPager);

        //setup get started button
        mImageView = (Button)findViewById(R.id.get_started);

        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(TutorialActivity.this, LoginActivity.class);
                startActivity(intent);
                finish();
            }
        });
    }
}

activity_tutorial_parallax.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

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

    <co.shutta.shuttapro.widgets.CircleIndicatorPager
        android:id="@+id/indicator"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="72dp"
        android:padding="5dp" />

    <Button
        android:id="@+id/get_started"
        android:layout_width="200dp"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="16dp"
        android:backgroundTint="@color/shutta_blue"
        android:text="@string/get_start"
        android:textColor="@color/white"
        android:textSize="16sp" />
</RelativeLayout>

CircleIndicatorPager.java:

public class CircleIndicatorPager extends View implements ViewPager.OnPageChangeListener {

    private int mCurrentPage;
    private float mPageOffset;
    private ViewPager mViewPager;
    private Paint mPaintFill;
    private Paint mPaintCur;

    public float getRadius() {
        return mRadius;
    }

    public void setRadius(float mRadius) {
        this.mRadius = mRadius;
    }

    private float mRadius;

    public CircleIndicatorPager(Context context) {
        super(context);
        init(context);
    }

    public CircleIndicatorPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public CircleIndicatorPager(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context ctx) {
        // Paint default
        mPaintFill = new Paint();
        setupPaint(mPaintFill, ctx.getResources().getColor(R.color.white_80));
        // Paint index
        mPaintCur = new Paint();
        setupPaint(mPaintCur, ctx.getResources().getColor(R.color.blue));
    }

    private void setupPaint(Paint paint, int color) {
        paint.setColor(color);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(mRadius);
        paint.setStyle(Paint.Style.FILL);
    }

    public void setViewPager(ViewPager view) {
        if (mViewPager == view) {
            return;
        }
        if (mViewPager != null) {
            mViewPager.setOnPageChangeListener(null);
        }
        if (view.getAdapter() == null) {
            throw new IllegalStateException("ViewPager does not have adapter instance.");
        }
        mViewPager = view;
        mViewPager.setOnPageChangeListener(this);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Update background indicator
        drawBackgroundCircle(canvas);
        // Update current indicator
        drawCurrentPageCircle(canvas);
    }

    private void drawBackgroundCircle(Canvas canvas) {
        final int pageNum = mViewPager.getAdapter().getCount();
        if (pageNum == 0) {
            return;
        }

        int centerX = canvas.getWidth() / 2;
        int centerY = canvas.getHeight() / 2;
        float indicatorWidth = pageNum * (6 * mRadius) - (4 * mRadius);
        float firstCirX = centerX - indicatorWidth / 2 + mRadius;
        float firstCirY = centerY;

        for (int i = 0; i < pageNum; i++) {
            float cX = firstCirX + i * (mRadius * 6);
            float cY = firstCirY;
            canvas.drawCircle(cX, cY, mRadius * 0.8f, mPaintFill);
        }
    }

    private void drawCurrentPageCircle(Canvas canvas) {
        final int pageNum = mViewPager.getAdapter().getCount();
        if (pageNum == 0) {
            return;
        }

        int centerX = canvas.getWidth() / 2;
        int centerY = canvas.getHeight() / 2;

        float indicatorWidth = pageNum * (6 * mRadius) - (4 * mRadius);
        float firstCirX = centerX - indicatorWidth / 2 + mRadius;
        float firstCirY = centerY;

        float cX = firstCirX + mCurrentPage * (mRadius * 6) + mPageOffset * 6 * mRadius;
        float cY = firstCirY;
        canvas.drawCircle(cX, cY, mRadius + 2, mPaintCur);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        mCurrentPage = position;
        //mPageOffset = positionOffset; //enable for slide animation, it looks stupid btw
        invalidate();
    }

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

TutorialParallaxAdapter.java:

public class TutorialParallaxAdapter extends FragmentStatePagerAdapter {

    private ArrayList<TutorialParallaxFragment> mFragments;
    private ViewPager mPager;

    public TutorialParallaxAdapter(FragmentManager fm) {
        super(fm);
        mFragments = new ArrayList<>();
    }

    @Override
    public Fragment getItem(int i) {
        return mFragments.get(i);
    }

    @Override
    public int getCount() {
        return mFragments.size();
    }

    public void add(TutorialParallaxFragment parallaxFragment) {
        parallaxFragment.setAdapter(this);
        mFragments.add(parallaxFragment);
        notifyDataSetChanged();
        mPager.setCurrentItem(getCount() - 1, true);

    }

    public void remove(int i) {
        mFragments.remove(i);
        notifyDataSetChanged();
    }

    public void remove(TutorialParallaxFragment parallaxFragment) {
        mFragments.remove(parallaxFragment);

        int pos = mPager.getCurrentItem();
        notifyDataSetChanged();

        mPager.setAdapter(this);
        if (pos >= this.getCount()) {
            pos = this.getCount() - 1;
        }
        mPager.setCurrentItem(pos, true);
    }

    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    public void setPager(ViewPager pager) {
        mPager = pager;
    }
}

TutorialParallaxFragment.java:

public class TutorialParallaxFragment extends Fragment {

    private TutorialParallaxAdapter mAdapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        View v = inflater.inflate(R.layout.fragment_tutorial_parallax, container, false);
        final ImageView image = (ImageView) v.findViewById(R.id.tutorial_image);

        image.setImageResource(getArguments().getInt("image"));
        image.post(new Runnable() {
            @Override
            public void run() {
                Matrix matrix = new Matrix();
                matrix.reset();

                float wv = image.getWidth();
                float hv = image.getHeight();

                float wi = image.getDrawable().getIntrinsicWidth();
                float hi = image.getDrawable().getIntrinsicHeight();

                float width = wv;
                float height = hv;

                if (wi / wv > hi / hv) {
                    matrix.setScale(hv / hi, hv / hi);
                    width = wi * hv / hi;
                } else {
                    matrix.setScale(wv / wi, wv / wi);
                    height= hi * wv / wi;
                }

                matrix.preTranslate((wv - width) / 2, (hv - height) / 2);
                image.setScaleType(ImageView.ScaleType.MATRIX);
                image.setImageMatrix(matrix);
            }
        });

        ImageView logo = (ImageView) v.findViewById(R.id.tutorial_logo);
        logo.setImageResource(getArguments().getInt("imageLogo"));

        ImageView imageText = (ImageView) v.findViewById(R.id.tutorial_text);
        imageText.setImageResource(getArguments().getInt("imageText"));

        return v;
    }

    public void setAdapter(TutorialParallaxAdapter adapter) {
        mAdapter = adapter;
    }
}

fragment_tutorial_parallax.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parallaxContent"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/tutorial_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="center"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"/>

    <ImageView
        android:id="@+id/tutorial_logo"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:paddingTop="50dp"
        android:layout_centerHorizontal="true" />

    <ImageView
        android:id="@+id/tutorial_text"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerInParent="true"
        android:layout_below="@id/tutorial_logo"/>
</RelativeLayout>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment