com.charon.scrollingtabs.view.ScrollingTabs.java Source code

Java tutorial

Introduction

Here is the source code for com.charon.scrollingtabs.view.ScrollingTabs.java

Source

/*
 * Copyright (C) 2013 Charon Chui <charon.chui@gmail.com>
 *
 * 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.charon.scrollingtabs.view;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class ScrollingTabs extends HorizontalScrollView implements OnPageChangeListener {

    protected LinearLayout mContainer;

    protected ViewPager mViewPager;

    protected TabAdapter mTabAdapter;

    protected int mWindowWidth;
    /**
     * True if have segmentation view between two tab view.
     */
    protected boolean isUseSeperator;

    protected TabClickListener mTabClickListener;

    protected PageSelectedListener mPageSelectedListener;

    /**
     * The width of the tab view, usually it may be 0.
     */
    protected int tabWidth;

    /**
     * True if you want to make make all the tabs equals the width when the total width is less than the window width
     */
    protected boolean mEqualWidth;

    public ScrollingTabs(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

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

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

    protected void init(Context context) {
        this.setHorizontalScrollBarEnabled(false);
        this.setHorizontalFadingEdgeEnabled(false);

        mContainer = new LinearLayout(context);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);
        mContainer.setLayoutParams(params);
        mContainer.setOrientation(LinearLayout.HORIZONTAL);

        addView(mContainer);

        mWindowWidth = getWindowWidth(context);
    }

    public static int getWindowWidth(Context context) {
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    public void setTabAdapter(TabAdapter adapter) {
        this.mTabAdapter = adapter;
        initTabView();
    }

    public void setViewPager(ViewPager pager) {
        this.mViewPager = pager;
        mViewPager.setOnPageChangeListener(this);
        initTabView();
    }

    /**
     * Add tab view.
     */
    private void initTabView() {
        int totalWidth = 0;

        if (mViewPager != null && mTabAdapter != null) {
            mContainer.removeAllViews();

            if (mEqualWidth) {
                for (int i = 0; i < mViewPager.getAdapter().getCount(); i++) {
                    View tab = mTabAdapter.getView(i);
                    measureView(tab);
                    totalWidth += tab.getWidth();

                    if (tab.getLayoutParams() != null) {
                        // int width = tab.getLayoutParams().width;
                        // int height = tab.getLayoutParams().height;
                    } else {
                        tab.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 100f));
                    }

                    if (mTabAdapter.getSeparator() != null && i != mViewPager.getAdapter().getCount() - 1) {
                        isUseSeperator = true;
                        measureView(mTabAdapter.getSeparator());
                        totalWidth += mTabAdapter.getSeparator().getWidth();
                    }
                }

                if (totalWidth < mWindowWidth) {
                    int count = mViewPager.getAdapter().getCount();
                    if (isUseSeperator) {
                        tabWidth = (mWindowWidth - (count - 1) * mTabAdapter.getSeparator().getWidth()) / count;
                    } else {
                        tabWidth = mWindowWidth / count;
                    }
                }
            }

            for (int i = 0; i < mViewPager.getAdapter().getCount(); i++) {
                final View tab = mTabAdapter.getView(i);
                tab.setTag(i);

                if (tabWidth != 0) {
                    mContainer.addView(tab, new LinearLayout.LayoutParams(tabWidth,
                            android.widget.LinearLayout.LayoutParams.MATCH_PARENT));
                } else {
                    mContainer.addView(tab,
                            new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 100f));
                }

                // Segmentation view
                if (mTabAdapter.getSeparator() != null && i != mViewPager.getAdapter().getCount() - 1) {
                    isUseSeperator = true;
                    mContainer.addView(mTabAdapter.getSeparator());
                }

                // Set click listener on tab.
                tab.setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        int index = (Integer) tab.getTag();
                        if (mTabClickListener != null) {
                            mTabClickListener.onClick(index);
                        } else {
                            if (mViewPager.getCurrentItem() == index) {
                                selectTab(index);
                            } else {
                                // If ViewPager change the page, the listener
                                // will call selectTab method
                                mViewPager.setCurrentItem(index, true);
                            }
                        }
                    }
                });

            }

            // Set the current selected tab when first coming.
            selectTab(mViewPager.getCurrentItem());
        }
    }

    /**
     * Select the tab, and move the tab to the middle position
     * 
     * @param position Position of the tab.
     */
    protected void selectTab(int position) {

        if (!isUseSeperator) {
            for (int i = 0; i < mContainer.getChildCount(); i++) {
                View tab = mContainer.getChildAt(i);
                // Make the current tab selected, others unselected.
                tab.setSelected(i == position);

                if (mTabAdapter != null) {
                    if (i == position) {
                        mTabAdapter.onTabSelected(position, mContainer);
                    } else {
                        mTabAdapter.onTabUnSelected(i, mContainer);
                    }
                }

            }
        } else {
            // pos is the position of the tab.
            for (int i = 0, pos = 0; i < mContainer.getChildCount(); i += 2, pos++) {
                View tab = mContainer.getChildAt(i);
                tab.setSelected(pos == position);

                if (mTabAdapter != null) {
                    if (pos == position) {
                        mTabAdapter.onTabSelected(i, mContainer);
                    } else {
                        mTabAdapter.onTabUnSelected(i, mContainer);
                    }
                }
            }
        }
        View selectedView = null;
        if (!isUseSeperator) {
            selectedView = mContainer.getChildAt(position);
        } else {
            selectedView = mContainer.getChildAt(position * 2);
        }

        int tabWidth = selectedView.getMeasuredWidth();
        int tabLeft = selectedView.getLeft();
        // (tabLeft + tabWidth / 2) is the distance from current tab's middle to
        // the left of the screen
        int distance = (tabLeft + tabWidth / 2) - mWindowWidth / 2;

        smoothScrollTo(distance, this.getScrollY());
    }

    protected View getSelectedView(int position) {
        View selectedView = null;
        if (!isUseSeperator) {
            selectedView = mContainer.getChildAt(position);
        } else {
            selectedView = mContainer.getChildAt(position * 2);
        }

        return selectedView;
    }

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

        if (changed) {
            selectTab(mViewPager.getCurrentItem());
        }
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {

    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {

    }

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

    /**
     * Set the tab width be all equals when all the tab width is less than the window width<br>
     * <font color=red>Note</font>This must be used before setTabAdapter and setViewPager
     * 
     * @param flag
     */
    public void setEqualWidth(boolean flag) {
        mEqualWidth = flag;
    }

    public void setTabClickListener(TabClickListener listener) {
        this.mTabClickListener = listener;
    }

    public void setPageSelectedListener(PageSelectedListener pageSelectedListener) {
        this.mPageSelectedListener = pageSelectedListener;
    }

    public static void measureView(View view) {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if (lp == null) {
            lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
        }

        int childMeasureWidth = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
        int childMeasureHeight;
        if (lp.height > 0) {
            childMeasureHeight = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
        } else {
            // Measure specification mode: The parent has not imposed any
            // constraint on the child. It can be whatever size it wants.
            childMeasureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(childMeasureWidth, childMeasureHeight);
    }

    /**
     * On click Listener of the tab.
     */
    public interface TabClickListener {
        public void onClick(int position);
    }

    /**
     * Callback when ViewPager change Pager.To avoid use setOnPageChangeListener more times will override.
     */
    public interface PageSelectedListener {
        public void onPageSelected(int position);
    }

    /**
     * Interface to get the tab view.
     * 
     * @author Charon Chui
     */
    public interface TabAdapter {
        /**
         * Tab View
         * 
         * @param position Position of the tab view.
         * @return View View of the tab.
         */
        public View getView(int position);

        /**
         * Segmentation view between two tab.
         * 
         * @return View, If don't use you this may return null.
         */
        public View getSeparator();

        /**
         * Callback when the tab is selected.
         * 
         * @param position Selected tab postion
         * @param mContainer The parent of all the tab.
         */
        public void onTabSelected(int position, ViewGroup mContainer);

        /**
         * Callback when the tab is unselected.
         * 
         * @param position Unselected tab postion
         * @param mContainer The parent of all the tab.
         */
        public void onTabUnSelected(int position, ViewGroup mContainer);
    }
}