PagerTabStrip.java revision 24cc55cb5775a71ff144a3588003fa8e52951c7d
124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell/*
224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * Copyright (C) 2012 The Android Open Source Project
324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell *
424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * you may not use this file except in compliance with the License.
624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * You may obtain a copy of the License at
724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell *
824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell *
1024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * Unless required by applicable law or agreed to in writing, software
1124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
1224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * See the License for the specific language governing permissions and
1424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * limitations under the License.
1524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell */
1624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
1724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellpackage android.support.v4.view;
1824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
1924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellimport android.content.Context;
2024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellimport android.graphics.Canvas;
2124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellimport android.graphics.Paint;
2224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellimport android.graphics.Rect;
2324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellimport android.util.AttributeSet;
2424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellimport android.view.View;
2524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
2624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell/**
2724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * PagerTabStrip is an interactive indicator of the current, next,
2824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * and previous pages of a {@link ViewPager}. It is intended to be used as a
2924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * child view of a ViewPager widget in your XML layout.
3024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * Add it as a child of a ViewPager in your layout file and set its
3124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * android:layout_gravity to TOP or BOTTOM to pin it to the top or bottom
3224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * of the ViewPager. The title from each page is supplied by the method
3324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * {@link PagerAdapter#getPageTitle(int)} in the adapter supplied to
3424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * the ViewPager.
3524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell *
3624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell * <p>For a non-interactive indicator, see {@link PagerTitleStrip}.</p>
3724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell */
3824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powellpublic class PagerTabStrip extends PagerTitleStrip {
3924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private static final int INDICATOR_HEIGHT = 3; // dp
4024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private static final int MIN_PADDING_BOTTOM = INDICATOR_HEIGHT + 3; // dp
4124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private static final int TAB_PADDING = 16; // dp
4224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private static final int TAB_SPACING = 32; // dp
4324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private static final int MIN_TEXT_SPACING = TAB_SPACING + TAB_PADDING * 2; // dp
4424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
4524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private int mIndicatorColor;
4624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private int mIndicatorHeight;
4724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
4824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private int mMinPaddingBottom;
4924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private int mMinTextSpacing;
5024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
5124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private int mTabPadding;
5224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
5324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private final Paint mTabPaint = new Paint();
5424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private final Rect mTempRect = new Rect();
5524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
5624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    private int mTabAlpha = 0xFF;
5724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
5824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public PagerTabStrip(Context context) {
5924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        this(context, null);
6024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
6124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
6224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public PagerTabStrip(Context context, AttributeSet attrs) {
6324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        super(context, attrs);
6424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
6524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mIndicatorColor = mTextColor;
6624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mTabPaint.setColor(mIndicatorColor);
6724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
6824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        // Note: this follows the rules for Resources#getDimensionPixelOffset/Size:
6924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        //       sizes round up, offsets round down.
7024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        final float density = context.getResources().getDisplayMetrics().density;
7124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mIndicatorHeight = (int) (INDICATOR_HEIGHT * density + 0.5f);
7224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mMinPaddingBottom = (int) (MIN_PADDING_BOTTOM * density + 0.5f);
7324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mMinTextSpacing = (int) (MIN_TEXT_SPACING * density);
7424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mTabPadding = (int) (TAB_PADDING * density + 0.5f);
7524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
7624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        // Enforce restrictions
7724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
7824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        setTextSpacing(getTextSpacing());
7924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
8024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        setWillNotDraw(false);
8124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
8224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mPrevText.setFocusable(true);
8324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mPrevText.setOnClickListener(new OnClickListener() {
8424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            @Override
8524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            public void onClick(View v) {
8624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell                mPager.setCurrentItem(mPager.getCurrentItem() - 1);
8724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            }
8824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        });
8924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
9024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mNextText.setFocusable(true);
9124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mNextText.setOnClickListener(new OnClickListener() {
9224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            @Override
9324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            public void onClick(View v) {
9424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell                mPager.setCurrentItem(mPager.getCurrentItem() + 1);
9524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            }
9624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        });
9724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
9824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
9924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    /**
10024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     * Set the color of the tab indicator bar.
10124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     *
10224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     * @param color Color to set as an 0xRRGGBB value. The high byte (alpha) is ignored.
10324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     */
10424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public void setTabIndicatorColor(int color) {
10524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mIndicatorColor = color;
10624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mTabPaint.setColor(mIndicatorColor);
10724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        invalidate();
10824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
10924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
11024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    /**
11124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     * Set the color of the tab indicator bar from a color resource.
11224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     *
11324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     * @param resId Resource ID of a color resource to load
11424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     */
11524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public void setTabIndicatorColorResource(int resId) {
11624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        setTabIndicatorColor(getContext().getResources().getColor(resId));
11724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
11824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
11924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    /**
12024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     * @return The current tab indicator color as an 0xRRGGBB value.
12124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell     */
12224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public int getTabIndicatorColor() {
12324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        return mIndicatorColor;
12424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
12524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
12624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    @Override
12724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public void setPadding(int left, int top, int right, int bottom) {
12824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        if (bottom < mMinPaddingBottom) {
12924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            bottom = mMinPaddingBottom;
13024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        }
13124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        super.setPadding(left, top, right, bottom);
13224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
13324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
13424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    @Override
13524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    public void setTextSpacing(int textSpacing) {
13624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        if (textSpacing < mMinTextSpacing) {
13724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell            textSpacing = mMinTextSpacing;
13824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        }
13924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        super.setTextSpacing(textSpacing);
14024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
14124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
14224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    @Override
14324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    protected void onDraw(Canvas canvas) {
14424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        super.onDraw(canvas);
14524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
14624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        final int bottom = getHeight();
14724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        final int left = mCurrText.getLeft() - mTabPadding;
14824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        final int right = mCurrText.getRight() + mTabPadding;
14924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        final int top = bottom - mIndicatorHeight;
15024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
15124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mTabPaint.setColor(mTabAlpha << 24 | (mIndicatorColor & 0xFFFFFF));
15224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        canvas.drawRect(left, top, right, bottom, mTabPaint);
15324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
15424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
15524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    @Override
15624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    void updateTextPositions(int position, float positionOffset, boolean force) {
15724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        final Rect r = mTempRect;
15824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        int bottom = getHeight();
15924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        int left = mCurrText.getLeft() - mTabPadding;
16024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        int right = mCurrText.getRight() + mTabPadding;
16124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        int top = bottom - mIndicatorHeight;
16224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
16324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        r.set(left, top, right, bottom);
16424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
16524cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        super.updateTextPositions(position, positionOffset, force);
16624cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        mTabAlpha = (int) (Math.abs(positionOffset - 0.5f) * 2 * 0xFF);
16724cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
16824cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        left = mCurrText.getLeft() - mTabPadding;
16924cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        right = mCurrText.getRight() + mTabPadding;
17024cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        r.union(left, top, right, bottom);
17124cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell
17224cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell        invalidate(r);
17324cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell    }
17424cc55cb5775a71ff144a3588003fa8e52951c7dAdam Powell}
175