com.github.omadahealth.slidepager.lib.SlidePager.java Source code

Java tutorial

Introduction

Here is the source code for com.github.omadahealth.slidepager.lib.SlidePager.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Omada Health, Inc
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.github.omadahealth.slidepager.lib;

import android.content.Context;
import android.content.res.TypedArray;
import android.databinding.BindingAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.github.omadahealth.slidepager.lib.adapter.AbstractSlidePagerAdapter;
import com.github.omadahealth.slidepager.lib.interfaces.OnSlidePageChangeListener;
import com.github.omadahealth.slidepager.lib.views.AbstractSlideView;
import com.github.omadahealth.slidepager.lib.views.ProgressView;

import java.util.List;

/**
 * Created by oliviergoutay and stoyand on 4/1/15.
 */
public class SlidePager extends ViewPager {
    /**
     * The tag for logging
     */
    private static final String TAG = "SlidePager";

    /**
     * A user defined {@link OnPageChangeListener} that can
     * be added to {@link #setOnPageChangeListener(OnPageChangeListener)}. The default page listener
     * is defined implemented by this class and set in {@link #setSlidePager()}
     */
    private OnSlidePageChangeListener mUserPageListener;

    /**
     * True if we should start at the last position in the {@link AbstractSlidePagerAdapter}
     */
    private boolean mStartAtEnd;

    /**
     * The attributes that this view is initialized with; need them to init the
     * child {@link ProgressView}s
     */
    private TypedArray mAttributes;

    /**
     * The page index saved to load the {@link com.github.omadahealth.slidepager.lib.views.SlideView} only once on
     * {@link android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrollStateChanged(int)}
     */
    private int mPageIndex;

    public SlidePager(Context context) {
        this(context, null);
    }

    public SlidePager(Context context, AttributeSet attrs) {
        super(context, attrs);
        loadStyledAttributes(attrs, 0);
        setSlidePager();
    }

    @Override
    public void setAdapter(PagerAdapter adapter) {
        if (!(adapter instanceof AbstractSlidePagerAdapter)) {
            throw new IllegalArgumentException("PagerAdapter should be a subclass of AbstractSlidePagerAdapter");
        }

        super.setAdapter(adapter);

        if (mStartAtEnd) {
            int position = adapter.getCount() - 1;
            setCurrentItem(position >= 0 ? position : 0);
        }
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        return i;
    }

    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        if (!(listener instanceof OnSlidePageChangeListener)) {
            throw new IllegalArgumentException(
                    "OnPageChangeListener should be a subclass of OnSlidePageChangeListener");
        }

        mUserPageListener = (OnSlidePageChangeListener) listener;
    }

    @Override
    public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
        if (!(transformer instanceof SlideTransformer)) {
            throw new IllegalArgumentException("Transformer should be a subclass of SlideTransformer");
        }

        if (getAdapter() == null) {
            super.setPageTransformer(reverseDrawingOrder, transformer);
            return;
        }

        if (getAdapter() instanceof AbstractSlidePagerAdapter) {
            transformer.transformPage(((AbstractSlidePagerAdapter) getAdapter()).getCurrentView(getCurrentItem()),
                    0);
            super.setPageTransformer(reverseDrawingOrder, transformer);
        }
    }

    /**
     * Fixes for "java.lang.IndexOutOfBoundsException Invalid index 0, size is 0"
     * on "android.support.v4.view.ViewPager.performDrag"
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i(TAG, "SlidePager click :" + (ev.getAction() & MotionEvent.ACTION_MASK));
        if (getAdapter() == null || getAdapter().getCount() == 0) {
            Log.i(TAG, "SlidePager onInterceptTouchEvent returned false because adapter is null or empty:");
            return false;
        }
        onTouchEvent(ev);
        try {
            return super.onInterceptTouchEvent(ev);
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return false;
    }

    /**
     * Fixes for "java.lang.IndexOutOfBoundsException Invalid index 0, size is 0"
     * on "android.support.v4.view.ViewPager.performDrag"
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (getAdapter() == null || getAdapter().getCount() == 0) {
            Log.i(TAG, "SlidePager onTouchEvent returned false because adapter is null or empty:");
            return false;
        }
        try {
            return super.onTouchEvent(event);
        } catch (Exception e) {
            Log.e(TAG, e.toString());
        }
        return false;
    }

    @BindingAdapter("sp_slide_show_circular_bars")
    public static void showCircularBars(SlidePager slidePager, Boolean visible) {
        if (visible == null) {
            visible = true;
        }
        ProgressView.setShowCircularBar(visible);
    }

    /**
     * Loads the styles and attributes defined in the xml tag of this class
     *
     * @param attrs        The attributes to read from
     * @param defStyleAttr The styles to read from
     */
    private void loadStyledAttributes(AttributeSet attrs, int defStyleAttr) {
        if (attrs != null) {
            setAttributeSet(
                    getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SlidePager, defStyleAttr, 0));
            mStartAtEnd = mAttributes.getBoolean(R.styleable.SlidePager_slide_start_at_end, false);
        }
    }

    /**
     * Sets the {@link #setOnPageChangeListener(OnPageChangeListener)} for this class. If the user wants
     * to link their own {@link android.support.v4.view.ViewPager.OnPageChangeListener} then they should
     * use {@link #setOnPageChangeListener(OnPageChangeListener)}; where we set {@link #mUserPageListener}
     */
    private void setSlidePager() {
        super.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                if (mUserPageListener != null) {
                    mUserPageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }
                mPageIndex = position;
            }

            @Override
            public void onPageSelected(int position) {
                if (mUserPageListener != null) {
                    mUserPageListener.onPageSelected(position);
                }
                resetPage(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                //page scrolled with room: drag, settle, idle
                //page scrolled when no room: drag, idle
                switch (state) {
                case ViewPager.SCROLL_STATE_DRAGGING:
                    animateStreaks(getCurrentItem(), false);
                    break;
                case ViewPager.SCROLL_STATE_SETTLING:
                    break;
                case ViewPager.SCROLL_STATE_IDLE://animate here onPageSelected not called when we hit a wall
                    Log.e(TAG, "SCROLL_STATE_IDLE for page index : " + getCurrentItem() + " mPageIndex : "
                            + mPageIndex);
                    if (getCurrentItem() == mPageIndex) {
                        animatePage(getCurrentItem());
                    }
                    break;
                }

                if (mUserPageListener != null) {
                    mUserPageListener.onPageScrollStateChanged(state);
                }
            }
        });
    }

    /**
     * Resets the {@link ProgressView} attributes to o progress and uncompleted colors.
     * Hides the series with {@link #animateStreaks(int, boolean)}
     *
     * @param position The position of the page to reset
     */
    @SuppressWarnings("unchecked")
    private void resetPage(int position) {
        if (getAdapter() != null) {
            AbstractSlideView slideView = ((AbstractSlidePagerAdapter) getAdapter()).getCurrentView(position);
            if (slideView != null) {
                slideView.resetPage(mAttributes);
            }
        }
    }

    /**
     * @param position
     */
    private void animatePage(int position) {
        AbstractSlideView slideView = ((AbstractSlidePagerAdapter) getAdapter()).getCurrentView(position);
        if (slideView != null) {
            slideView.animatePage(mUserPageListener, mAttributes);
        }
    }

    /**
     * @param position
     * @param show
     */
    private void animateStreaks(int position, boolean show) {
        AbstractSlideView slideView = ((AbstractSlidePagerAdapter) getAdapter()).getCurrentView(position);
        slideView.resetStreaks(show);
    }

    /**
     * Returns the initiated child views in {@link SlideTransformer#initTags(View)}
     *
     * @param position
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<View> getChildren(int position) {
        View selectedView = (((AbstractSlidePagerAdapter) getAdapter()).getCurrentView(position));

        if (selectedView.getTag() == null) {
            SlideTransformer.initTags(selectedView);
        }

        return (List<View>) selectedView.getTag(R.id.slide_transformer_tag_key);
    }

    /**
     * Refreshes the page animation
     */
    public void refreshPage() {
        animatePage(getCurrentItem());
    }

    /**
     * Gets the attribute set that we pass from xml attr in {@link R.styleable#SlidePager}
     * in {@link #loadStyledAttributes(AttributeSet, int)}
     *
     * @return
     */
    public TypedArray getAttributeSet() {
        return mAttributes;
    }

    /**
     * Sets the {@link #mAttributes} that are passed on to the {@link ProgressView} and {@link android.transition.Slide}
     *
     * @param attributeSet
     */

    public void setAttributeSet(TypedArray attributeSet) {
        this.mAttributes = attributeSet;
    }
}