Please note that the contents of this offline web site may be out of date. To access the most recent documentation visit the online version .
Note that links that point to online resources are green in color and will open in a new window.
We would love it if you could give us feedback about this material by filling this form (You have to be online to fill it)
FragmentTransition / src / com.example.android.common / view /

SlidingTabLayout.java

      
        1
       
        2
       
        3
       
        4
       
        5
       
        6
       
        7
       
        8
       
        9
       
        10
       
        11
       
        12
       
        13
       
        14
       
        15
       
        16
       
        17
       
        18
       
        19
       
        20
       
        21
       
        22
       
        23
       
        24
       
        25
       
        26
       
        27
       
        28
       
        29
       
        30
       
        31
       
        32
       
        33
       
        34
       
        35
       
        36
       
        37
       
        38
       
        39
       
        40
       
        41
       
        42
       
        43
       
        44
       
        45
       
        46
       
        47
       
        48
       
        49
       
        50
       
        51
       
        52
       
        53
       
        54
       
        55
       
        56
       
        57
       
        58
       
        59
       
        60
       
        61
       
        62
       
        63
       
        64
       
        65
       
        66
       
        67
       
        68
       
        69
       
        70
       
        71
       
        72
       
        73
       
        74
       
        75
       
        76
       
        77
       
        78
       
        79
       
        80
       
        81
       
        82
       
        83
       
        84
       
        85
       
        86
       
        87
       
        88
       
        89
       
        90
       
        91
       
        92
       
        93
       
        94
       
        95
       
        96
       
        97
       
        98
       
        99
       
        100
       
        101
       
        102
       
        103
       
        104
       
        105
       
        106
       
        107
       
        108
       
        109
       
        110
       
        111
       
        112
       
        113
       
        114
       
        115
       
        116
       
        117
       
        118
       
        119
       
        120
       
        121
       
        122
       
        123
       
        124
       
        125
       
        126
       
        127
       
        128
       
        129
       
        130
       
        131
       
        132
       
        133
       
        134
       
        135
       
        136
       
        137
       
        138
       
        139
       
        140
       
        141
       
        142
       
        143
       
        144
       
        145
       
        146
       
        147
       
        148
       
        149
       
        150
       
        151
       
        152
       
        153
       
        154
       
        155
       
        156
       
        157
       
        158
       
        159
       
        160
       
        161
       
        162
       
        163
       
        164
       
        165
       
        166
       
        167
       
        168
       
        169
       
        170
       
        171
       
        172
       
        173
       
        174
       
        175
       
        176
       
        177
       
        178
       
        179
       
        180
       
        181
       
        182
       
        183
       
        184
       
        185
       
        186
       
        187
       
        188
       
        189
       
        190
       
        191
       
        192
       
        193
       
        194
       
        195
       
        196
       
        197
       
        198
       
        199
       
        200
       
        201
       
        202
       
        203
       
        204
       
        205
       
        206
       
        207
       
        208
       
        209
       
        210
       
        211
       
        212
       
        213
       
        214
       
        215
       
        216
       
        217
       
        218
       
        219
       
        220
       
        221
       
        222
       
        223
       
        224
       
        225
       
        226
       
        227
       
        228
       
        229
       
        230
       
        231
       
        232
       
        233
       
        234
       
        235
       
        236
       
        237
       
        238
       
        239
       
        240
       
        241
       
        242
       
        243
       
        244
       
        245
       
        246
       
        247
       
        248
       
        249
       
        250
       
        251
       
        252
       
        253
       
        254
       
        255
       
        256
       
        257
       
        258
       
        259
       
        260
       
        261
       
        262
       
        263
       
        264
       
        265
       
        266
       
        267
       
        268
       
        269
       
        270
       
        271
       
        272
       
        273
       
        274
       
        275
       
        276
       
        277
       
        278
       
        279
       
        280
       
        281
       
        282
       
        283
       
        284
       
        285
       
        286
       
        287
       
        288
       
        289
       
        290
       
        291
       
        292
       
        293
       
        294
       
        295
       
        296
       
        297
       
        298
       
        299
       
        300
       
        301
       
        302
       
        303
       
        304
       
        305
       
        306
       
        307
       
        308
       
        309
       
        310
       
        311
       
        312
       
        313
       
        314
       
       
       

       
/*
       

       
       

        * Copyright (C) 2013 The Android Open Source Project
       

       
       

        *
       

       
       

        * 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.example.android.common.view;
       

       
       

       

       
       

       
import android.content.Context;
       

       
       

       
import android.graphics.Typeface;
       

       
       

       
import android.os.Build;
       

       
       

       
import android.support.v4.view.PagerAdapter;
       

       
       

       
import android.support.v4.view.ViewPager;
       

       
       

       
import android.util.AttributeSet;
       

       
       

       
import android.util.TypedValue;
       

       
       

       
import android.view.Gravity;
       

       
       

       
import android.view.LayoutInflater;
       

       
       

       
import android.view.View;
       

       
       

       
import android.widget.HorizontalScrollView;
       

       
       

       
import android.widget.TextView;
       

       
       

       

       
       

       
/**
       

       
       

        * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
       

       
       

        * the user's scroll progress.
       

       
       

        * <p>
       

       
       

        * To use the component, simply add it to your view hierarchy. Then in your
       

       
       

        * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
       

       
       

        * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
       

       
       

        * <p>
       

       
       

        * The colors can be customized in two ways. The first and simplest is to provide an array of colors
       

       
       

        * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
       

       
       

        * alternative is via the {@link TabColorizer} interface which provides you complete control over
       

       
       

        * which color is used for any individual position.
       

       
       

        * <p>
       

       
       

        * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
       

       
       

        * providing the layout ID of your custom layout.
       

       
       

        */

       

       
       

       
public class SlidingTabLayout extends HorizontalScrollView {
       

       
       

       

       
       

       
/**
       

       
       

        * Allows complete control over the colors drawn in the tab layout. Set with
       

       
       

        * {@link #setCustomTabColorizer(TabColorizer)}.
       

       
       

        */

       

       
       

       
public interface TabColorizer {
       

       
       

       

       
       

       
/**
       

       
       

        * @return return the color of the indicator used when {@code position} is selected.
       

       
       

        */

       

       
       

       
int getIndicatorColor(int position);
       

       
       

       

       
       

       
/**
       

       
       

        * @return return the color of the divider drawn to the right of {@code position}.
       

       
       

        */

       

       
       

       
int getDividerColor(int position);
       

       
       

       

       
       

       
}
       

       
       

       

       
       

       
private static final int TITLE_OFFSET_DIPS = 24;
       

       
       

       
private static final int TAB_VIEW_PADDING_DIPS = 16;
       

       
       

       
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
       

       
       

       

       
       

       
private int mTitleOffset;
       

       
       

       

       
       

       
private int mTabViewLayoutId;
       

       
       

       
private int mTabViewTextViewId;
       

       
       

       

       
       

       
private ViewPager mViewPager;
       

       
       

       
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
       

       
       

       

       
       

       
private final SlidingTabStrip mTabStrip;
       

       
       

       

       
       

       
public SlidingTabLayout(Context context) {
       

       
       

       
this(context, null);
       

       
       

       
}
       

       
       

       

       
       

       
public SlidingTabLayout(Context context, AttributeSet attrs) {
       

       
       

       
this(context, attrs, 0);
       

       
       

       
}
       

       
       

       

       
       

       
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
       

       
       

       
super(context, attrs, defStyle);
       

       
       

       

       
       

       
// Disable the Scroll Bar
       

       
       

        setHorizontalScrollBarEnabled
(false);
       

       
       

       
// Make sure that the Tab Strips fills this View
       

       
       

        setFillViewport
(true);
       

       
       

       

       
       

        mTitleOffset
= (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
       

       
       

       

       
       

        mTabStrip
= new SlidingTabStrip(context);
       

       
       

        addView
(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Set the custom {@link TabColorizer} to be used.
       

       
       

        *
       

       
       

        * If you only require simple custmisation then you can use
       

       
       

        * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
       

       
       

        * similar effects.
       

       
       

        */

       

       
       

       
public void setCustomTabColorizer(TabColorizer tabColorizer) {
       

       
       

        mTabStrip
.setCustomTabColorizer(tabColorizer);
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Sets the colors to be used for indicating the selected tab. These colors are treated as a
       

       
       

        * circular array. Providing one color will mean that all tabs are indicated with the same color.
       

       
       

        */

       

       
       

       
public void setSelectedIndicatorColors(int... colors) {
       

       
       

        mTabStrip
.setSelectedIndicatorColors(colors);
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
       

       
       

        * Providing one color will mean that all tabs are indicated with the same color.
       

       
       

        */

       

       
       

       
public void setDividerColors(int... colors) {
       

       
       

        mTabStrip
.setDividerColors(colors);
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
       

       
       

        * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
       

       
       

        * that the layout can update it's scroll position correctly.
       

       
       

        *
       

       
       

        * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
       

       
       

        */

       

       
       

       
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
       

       
       

        mViewPagerPageChangeListener
= listener;
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Set the custom layout to be inflated for the tab views.
       

       
       

        *
       

       
       

        * @param layoutResId Layout id to be inflated
       

       
       

        * @param textViewId id of the {@link TextView} in the inflated view
       

       
       

        */

       

       
       

       
public void setCustomTabView(int layoutResId, int textViewId) {
       

       
       

        mTabViewLayoutId
= layoutResId;
       

       
       

        mTabViewTextViewId
= textViewId;
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Sets the associated view pager. Note that the assumption here is that the pager content
       

       
       

        * (number of tabs and tab titles) does not change after this call has been made.
       

       
       

        */

       

       
       

       
public void setViewPager(ViewPager viewPager) {
       

       
       

        mTabStrip
.removeAllViews();
       

       
       

       

       
       

        mViewPager
= viewPager;
       

       
       

       
if (viewPager != null) {
       

       
       

        viewPager
.setOnPageChangeListener(new InternalViewPagerListener());
       

       
       

        populateTabStrip
();
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
/**
       

       
       

        * Create a default view to be used for tabs. This is called if a custom tab view is not set via
       

       
       

        * {@link #setCustomTabView(int, int)}.
       

       
       

        */

       

       
       

       
protected TextView createDefaultTabView(Context context) {
       

       
       

       
TextView textView = new TextView(context);
       

       
       

        textView
.setGravity(Gravity.CENTER);
       

       
       

        textView
.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
       

       
       

        textView
.setTypeface(Typeface.DEFAULT_BOLD);
       

       
       

       

       
       

       
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
       

       
       

       
// If we're running on Honeycomb or newer, then we can use the Theme's
       

       
       

       
// selectableItemBackground to ensure that the View has a pressed state
       

       
       

       
TypedValue outValue = new TypedValue();
       

       
       

        getContext
().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
       

       
       

        outValue
, true);
       

       
       

        textView
.setBackgroundResource(outValue.resourceId);
       

       
       

       
}
       

       
       

       

       
       

       
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
       

       
       

       
// If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
       

       
       

        textView
.setAllCaps(true);
       

       
       

       
}
       

       
       

       

       
       

       
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
       

       
       

        textView
.setPadding(padding, padding, padding, padding);
       

       
       

       

       
       

       
return textView;
       

       
       

       
}
       

       
       

       

       
       

       
private void populateTabStrip() {
       

       
       

       
final PagerAdapter adapter = mViewPager.getAdapter();
       

       
       

       
final View.OnClickListener tabClickListener = new TabClickListener();
       

       
       

       

       
       

       
for (int i = 0; i < adapter.getCount(); i++) {
       

       
       

       
View tabView = null;
       

       
       

       
TextView tabTitleView = null;
       

       
       

       

       
       

       
if (mTabViewLayoutId != 0) {
       

       
       

       
// If there is a custom tab view layout id set, try and inflate it
       

       
       

        tabView
= LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
       

       
       

       
false);
       

       
       

        tabTitleView
= (TextView) tabView.findViewById(mTabViewTextViewId);
       

       
       

       
}
       

       
       

       

       
       

       
if (tabView == null) {
       

       
       

        tabView
= createDefaultTabView(getContext());
       

       
       

       
}
       

       
       

       

       
       

       
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
       

       
       

        tabTitleView
= (TextView) tabView;
       

       
       

       
}
       

       
       

       

       
       

        tabTitleView
.setText(adapter.getPageTitle(i));
       

       
       

        tabView
.setOnClickListener(tabClickListener);
       

       
       

       

       
       

        mTabStrip
.addView(tabView);
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
@Override
       

       
       

       
protected void onAttachedToWindow() {
       

       
       

       
super.onAttachedToWindow();
       

       
       

       

       
       

       
if (mViewPager != null) {
       

       
       

        scrollToTab
(mViewPager.getCurrentItem(), 0);
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
private void scrollToTab(int tabIndex, int positionOffset) {
       

       
       

       
final int tabStripChildCount = mTabStrip.getChildCount();
       

       
       

       
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
       

       
       

       
return;
       

       
       

       
}
       

       
       

       

       
       

       
View selectedChild = mTabStrip.getChildAt(tabIndex);
       

       
       

       
if (selectedChild != null) {
       

       
       

       
int targetScrollX = selectedChild.getLeft() + positionOffset;
       

       
       

       

       
       

       
if (tabIndex > 0 || positionOffset > 0) {
       

       
       

       
// If we're not at the first child and are mid-scroll, make sure we obey the offset
       

       
       

        targetScrollX
-= mTitleOffset;
       

       
       

       
}
       

       
       

       

       
       

        scrollTo
(targetScrollX, 0);
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
       

       
       

       
private int mScrollState;
       

       
       

       

       
       

       
@Override
       

       
       

       
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       

       
       

       
int tabStripChildCount = mTabStrip.getChildCount();
       

       
       

       
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
       

       
       

       
return;
       

       
       

       
}
       

       
       

       

       
       

        mTabStrip
.onViewPagerPageChanged(position, positionOffset);
       

       
       

       

       
       

       
View selectedTitle = mTabStrip.getChildAt(position);
       

       
       

       
int extraOffset = (selectedTitle != null)
       

       
       

       
? (int) (positionOffset * selectedTitle.getWidth())
       

       
       

       
: 0;
       

       
       

        scrollToTab
(position, extraOffset);
       

       
       

       

       
       

       
if (mViewPagerPageChangeListener != null) {
       

       
       

        mViewPagerPageChangeListener
.onPageScrolled(position, positionOffset,
       

       
       

        positionOffsetPixels
);
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
@Override
       

       
       

       
public void onPageScrollStateChanged(int state) {
       

       
       

        mScrollState
= state;
       

       
       

       

       
       

       
if (mViewPagerPageChangeListener != null) {
       

       
       

        mViewPagerPageChangeListener
.onPageScrollStateChanged(state);
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
@Override
       

       
       

       
public void onPageSelected(int position) {
       

       
       

       
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
       

       
       

        mTabStrip
.onViewPagerPageChanged(position, 0f);
       

       
       

        scrollToTab
(position, 0);
       

       
       

       
}
       

       
       

       

       
       

       
if (mViewPagerPageChangeListener != null) {
       

       
       

        mViewPagerPageChangeListener
.onPageSelected(position);
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
}
       

       
       

       

       
       

       
private class TabClickListener implements View.OnClickListener {
       

       
       

       
@Override
       

       
       

       
public void onClick(View v) {
       

       
       

       
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
       

       
       

       
if (v == mTabStrip.getChildAt(i)) {
       

       
       

        mViewPager
.setCurrentItem(i);
       

       
       

       
return;
       

       
       

       
}
       

       
       

       
}
       

       
       

       
}
       

       
       

       
}
       

       
       

       

       
       

       
}