com.cicada.startup.common.ui.view.indicator.ViewPagerIndicator.java Source code

Java tutorial

Introduction

Here is the source code for com.cicada.startup.common.ui.view.indicator.ViewPagerIndicator.java

Source

/*
 * Copyright (C) 2013 Peng fei Pan <sky@xiaopan.me>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cicada.startup.common.ui.view.indicator;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.Scroller;

import com.cicada.startup.common.R;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * <p/>
 * : 16/7/12 ?3:13 <br/>
 *
 * @author zhaohaiyang
 * @since v0.0.1
 */
public class ViewPagerIndicator extends HorizontalScrollView implements View.OnClickListener {
    private int currentPosition; // ??
    private int lastOffset;
    private int lastScrollX = 0;
    private float currentPositionOffset; // ?????
    private boolean start;
    private boolean allowWidthFull; // ?Item
    private boolean disableViewPager; // ?ViewPager
    private View currentSelectedTabView; // ?
    private Drawable slidingBlockDrawable; // ?
    private ViewPager viewPager; // ViewPager
    private ViewGroup tabsLayout; // 
    private ViewPager.OnPageChangeListener onPageChangeListener; // ???
    private OnClickTabListener onClickTabListener;
    private OnPagerChangeLis listener;
    private List<View> tabViews;

    private int slidingBlockHeight = 8;

    private Scroller scroller;

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

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        setHorizontalScrollBarEnabled(false); // ??????
        scroller = new Scroller(context);

        if (attrs != null) {
            TypedArray attrsTypedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
            if (attrsTypedArray != null) {
                allowWidthFull = attrsTypedArray.getBoolean(R.styleable.ViewPagerIndicator_allowWidthFull, false);
                slidingBlockDrawable = attrsTypedArray.getDrawable(R.styleable.ViewPagerIndicator_slidingBlock);
                slidingBlockHeight = (int) attrsTypedArray
                        .getDimension(R.styleable.ViewPagerIndicator_slidingBlockHeight, 8);
                disableViewPager = attrsTypedArray.getBoolean(R.styleable.ViewPagerIndicator_disableViewPager,
                        false);
                attrsTypedArray.recycle();
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!allowWidthFull) {
            return;
        }
        setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + slidingBlockHeight);
        ViewGroup tabsLayout = getTabsLayout();
        if (tabsLayout == null || tabsLayout.getMeasuredWidth() >= getMeasuredWidth())
            return;
        if (tabsLayout.getChildCount() <= 0)
            return;

        if (tabViews == null) {
            tabViews = new ArrayList<View>();
        } else {
            tabViews.clear();
        }
        for (int w = 0; w < tabsLayout.getChildCount(); w++) {
            tabViews.add(tabsLayout.getChildAt(w));
        }

        adjustChildWidthWithParent(tabViews,
                getMeasuredWidth() - tabsLayout.getPaddingLeft() - tabsLayout.getPaddingRight(), widthMeasureSpec,
                heightMeasureSpec);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * views?ViewView?parentViewWidth
     *
     * @param views                   ?View?
     * @param parentViewWidth         Vie
     * @param parentWidthMeasureSpec  View
     * @param parentHeightMeasureSpec View
     */
    private void adjustChildWidthWithParent(List<View> views, int parentViewWidth, int parentWidthMeasureSpec,
            int parentHeightMeasureSpec) {
        // ?View?
        for (View view : views) {
            if (view.getLayoutParams() instanceof MarginLayoutParams) {
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) view.getLayoutParams();
                parentViewWidth -= lp.leftMargin + lp.rightMargin;
            }
        }

        // ?View???
        int tabCount = views.size();
        int averageWidth = parentViewWidth / tabCount;
        while (true) {
            Iterator<View> iterator = views.iterator();
            while (iterator.hasNext()) {
                View view = iterator.next();
                if (view.getMeasuredWidth() > averageWidth) {
                    parentViewWidth -= view.getMeasuredWidth();
                    tabCount--;
                    iterator.remove();
                }
            }
            averageWidth = parentViewWidth / tabCount;
            boolean end = true;
            for (View view : views) {
                if (view.getMeasuredWidth() > averageWidth) {
                    end = false;
                }
            }
            if (end) {
                break;
            }
        }

        // ??View
        for (View view : views) {
            if (view.getMeasuredWidth() < averageWidth) {
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams();
                layoutParams.width = averageWidth;
                view.setLayoutParams(layoutParams);
                // ??
                if (layoutParams instanceof MarginLayoutParams) {
                    measureChildWithMargins(view, parentWidthMeasureSpec, 0, parentHeightMeasureSpec, 0);
                } else {
                    measureChild(view, parentWidthMeasureSpec, parentHeightMeasureSpec);
                }
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        ViewGroup tabViewGroup = getTabsLayout();
        if (tabViewGroup != null) {
            // ?????
            currentPosition = viewPager != null ? viewPager.getCurrentItem() : 0;
            if (!disableViewPager) {
                scrollToChild(currentPosition, 0); // ??
                selectedTab(currentPosition); // ?TAB
            }

            // ?tab?Pager
            for (int w = 0; w < tabViewGroup.getChildCount(); w++) {
                View itemView = tabViewGroup.getChildAt(w);
                itemView.setTag(w);
                itemView.setOnClickListener(this);
            }
        }
    }

    @Override
    public void onClick(View v) {
        int index = (Integer) v.getTag();
        if (onClickTabListener != null) {
            onClickTabListener.onClickTab(v, index);
        }
        if (viewPager != null) {
            viewPager.setCurrentItem(index, false);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (disableViewPager)
            return;
        /* ? */
        ViewGroup tabsLayout = getTabsLayout();
        if (tabsLayout != null && tabsLayout.getChildCount() > 0 && slidingBlockDrawable != null) {
            View currentTab = tabsLayout.getChildAt(currentPosition);
            if (currentTab != null) {
                float slidingBlockLeft = getTabTextLeft((ViewGroup) currentTab);
                float slidingBlockRight = getTabTextRight((ViewGroup) currentTab);
                if (currentPositionOffset > 0f && currentPosition < tabsLayout.getChildCount() - 1) {
                    View nextTab = tabsLayout.getChildAt(currentPosition + 1);
                    if (nextTab != null) {
                        final float nextTabLeft = getTabTextLeft((ViewGroup) nextTab);
                        final float nextTabRight = getTabTextRight((ViewGroup) nextTab);
                        slidingBlockLeft = (currentPositionOffset * nextTabLeft
                                + (1f - currentPositionOffset) * slidingBlockLeft);
                        slidingBlockRight = (currentPositionOffset * nextTabRight
                                + (1f - currentPositionOffset) * slidingBlockRight);
                    }
                }
                slidingBlockDrawable.setBounds((int) slidingBlockLeft, getHeight() - slidingBlockHeight,
                        (int) slidingBlockRight, getHeight());
                slidingBlockDrawable.draw(canvas);
            }
        }
    }

    private int getTabTextLeft(ViewGroup parentView) {
        View childView = parentView.getChildAt(0);

        return parentView.getLeft() + childView.getPaddingLeft();
    }

    private int getTabTextRight(ViewGroup parentView) {
        View childView = parentView.getChildAt(0);

        return parentView.getRight() - childView.getPaddingRight();
    }

    /**
     * ?
     */
    private ViewGroup getTabsLayout() {
        if (tabsLayout == null) {
            if (getChildCount() > 0) {
                tabsLayout = (ViewGroup) getChildAt(0);
            } else {
                removeAllViews();
                tabsLayout = new LinearLayout(getContext());
                addView(tabsLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
            }
        }
        return tabsLayout;
    }

    /**
     * ?
     */
    private void scrollToChild(int position, int offset) {
        ViewGroup tabsLayout = getTabsLayout();
        if (tabsLayout != null && tabsLayout.getChildCount() > 0 && position < tabsLayout.getChildCount()) {
            View view = tabsLayout.getChildAt(position);
            if (view != null) {
                // X??
                int newScrollX = view.getLeft() + offset;
                if (position > 0 || offset > 0) {
                    newScrollX -= 240 - getOffset(view.getWidth()) / 2;
                }

                // ?X???
                if (newScrollX != lastScrollX) {
                    lastScrollX = newScrollX;
                    scrollTo(newScrollX, 0);
                }
            }
        }
    }

    /**
     * ????
     */
    private int getOffset(int newOffset) {
        if (lastOffset < newOffset) {
            if (start) {
                lastOffset += 1;
                return lastOffset;
            } else {
                start = true;
                lastOffset += 1;
                return lastOffset;
            }
        }
        if (lastOffset > newOffset) {
            if (start) {
                lastOffset -= 1;
                return lastOffset;
            } else {
                start = true;
                lastOffset -= 1;
                return lastOffset;
            }
        } else {
            start = true;
            lastOffset = newOffset;
            return lastOffset;
        }
    }

    /**
     * ?TAB
     */
    private void selectedTab(int currentSelectedTabPosition) {
        ViewGroup tabsLayout = getTabsLayout();
        if (currentSelectedTabPosition > -1 && tabsLayout != null
                && currentSelectedTabPosition < tabsLayout.getChildCount()) {
            if (currentSelectedTabView != null) {
                currentSelectedTabView.setSelected(false);
            }
            currentSelectedTabView = tabsLayout.getChildAt(currentSelectedTabPosition);
            if (currentSelectedTabView != null) {
                currentSelectedTabView.setSelected(true);
            }
        }
    }

    /**
     * Tab
     */
    public void addTab(View tabView, int index) {
        if (tabView != null) {
            getTabsLayout().addView(tabView, index);
            requestLayout();
        }
    }

    /**
     * Tab
     */
    public void addTab(View tabView) {
        addTab(tabView, -1);
    }

    /**
     * Tab
     *
     * @param tabViews ?Tab
     */
    public void addTab(View... tabViews) {
        if (tabViews != null) {
            for (View view : tabViews) {
                getTabsLayout().addView(view);
            }
            requestLayout();
        }
    }

    /**
     * Tab
     */
    public void addTab(List<View> tabViews) {
        if (tabViews != null) {
            for (View view : tabViews) {
                getTabsLayout().addView(view);
            }
            requestLayout();
        }
    }

    /**
     * tab
     *
     * @param index
     */
    public void removeTab(int index) {
        removeTab(index, 1);
    }

    /**
     * tab
     *
     * @param start ?
     * @param count ?
     */
    public void removeTab(int start, int count) {
        int tabCount = getTabCount();
        if (start < 0 || start > tabCount) {
            start = 0;
        }
        if (count < 0 || count > tabCount) {
            count = 1;
        }
        if (count - start > tabCount) {
            count = tabCount - start;
        }

        getTabsLayout().removeViews(start, count);
        requestLayout();
    }

    /**
     * 
     */
    public void removeAllTab() {
        getTabsLayout().removeAllViews();
        requestLayout();
    }

    public View getChild(int idx) {
        return getTabsLayout().getChildAt(idx);
    }

    /**
     * ViewPager
     *
     * @param viewPager ViewPager
     */
    public void setViewPager(ViewPager viewPager) {
        if (disableViewPager)
            return;
        this.viewPager = viewPager;
        this.viewPager.setOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                selectedTab(position);
                if (onPageChangeListener != null) {
                    onPageChangeListener.onPageSelected(position);
                }
                if (listener != null)
                    listener.onChanged(position);
            }

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

                ViewGroup tabsLayout = getTabsLayout();
                if (nextPagePosition < tabsLayout.getChildCount()) {
                    View view = tabsLayout.getChildAt(nextPagePosition);
                    if (view != null) {
                        currentPosition = nextPagePosition;
                        currentPositionOffset = positionOffset;
                        scrollToChild(nextPagePosition, (int) (positionOffset * view.getWidth()));
                        invalidate();
                    }
                }
                if (onPageChangeListener != null) {
                    onPageChangeListener.onPageScrolled(nextPagePosition, positionOffset, positionOffsetPixels);
                }
            }

            @Override
            public void onPageScrollStateChanged(int arg0) {
                if (onPageChangeListener != null) {
                    onPageChangeListener.onPageScrollStateChanged(arg0);
                }
            }
        });
        requestLayout();
    }

    /**
     * Page??
     *
     * @param onPageChangeListener Page??
     */
    public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
        this.onPageChangeListener = onPageChangeListener;
    }

    /**
     * ??
     *
     * @param allowWidthFull true??Item?
     */
    public void setAllowWidthFull(boolean allowWidthFull) {
        this.allowWidthFull = allowWidthFull;
        requestLayout();
    }

    /**
     * ?
     */
    public void setSlidingBlockDrawable(Drawable slidingBlockDrawable) {
        this.slidingBlockDrawable = slidingBlockDrawable;
        requestLayout();
    }

    /**
     * ?Tab
     */
    public int getTabCount() {
        ViewGroup tabsLayout = getTabsLayout();
        return tabsLayout != null ? tabsLayout.getChildCount() : 0;
    }

    /**
     * Tab?
     *
     * @param onClickTabListener Tab?
     */
    public void setOnClickTabListener(OnClickTabListener onClickTabListener) {
        this.onClickTabListener = onClickTabListener;
    }

    /**
     * ?ViewPager
     *
     * @param disableViewPager ?ViewPager
     */
    public void setDisableViewPager(boolean disableViewPager) {
        this.disableViewPager = disableViewPager;
        if (viewPager != null) {
            viewPager.setOnPageChangeListener(onPageChangeListener);
            viewPager = null;
        }
        requestLayout();
    }

    /**
     * Tab?
     *
     * @author xiaopan
     */
    public interface OnClickTabListener {
        public void onClickTab(View tab, int index);
    }

    public void setOnPagerChange(OnPagerChangeLis l) {
        this.listener = l;
    }

    public interface OnPagerChangeLis {
        void onChanged(int page);
    }
}