從
http://developer.android.com/intl/zh-cn/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html下載SlidingTabsLayout的樣例,主要類是:SlidingTabsLayout 、SlidingTabStrip,將這兩個類復制到項目中。
SlidingTabsLayout的用法:
1. SlidingTabsLayout:對導航欄設置屬性,該類設置屬性的方法較少(如設置欄目的權重等)
1.1 常量介紹
//選項卡的位移長度 private static final int TITLE_OFFSET_DIPS = 24; //選項卡中textview的間距 private static final int TAB_VIEW_PADDING_DIPS = 16; //選項卡中textview文字的大小 private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
1.2 根據內部接口實現設置自定義選項卡
/** * 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); }
1.3 設置選項卡選中時指示線的顏色
/** * 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); }
1.4 設置分割線的顏色
/** * 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); }
1.5 設置自定義選項的資源文件
/** * 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; }
1.6 創建默認的選項
/** * 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; }
1.7 構建選項導航卡展示的內容
//構建選項導航卡展示的內容,通過addView加入 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); } }
1.8 選項卡導航切換
//選項導航切換 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); } }
1.9 viewpager改變視圖的監聽類
//viewpager改變視圖監聽類 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); } } }
1.10 選項導航卡的點擊事件
//選項導航卡的點擊事件 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; } } } }
2. SlidingTabStrip:描繪導航欄的類,通過onDraw方法
2.1 常量介紹
//選項卡底部長線的默認厚度 private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; //選項卡底部長線的默認顏色透明度 private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; //選項卡選中時指示線的厚度(不能低於底部長線的值,不然會被覆蓋) private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8; //選項卡選中時指示線的默認顏色 private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; //分割線的默認厚度 private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; //分割線的默認顏色透明度 private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; //分割線默認高度 private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f; //選項卡底部長線厚度(根據屏幕密度計算所得) private final int mBottomBorderThickness; private final Paint mBottomBorderPaint; //選項卡底部指示線厚度(根據屏幕密度計算所得) private final int mSelectedIndicatorThickness; private final Paint mSelectedIndicatorPaint; private final int mDefaultBottomBorderColor; private final Paint mDividerPaint; //選項卡分割線高度 private final float mDividerHeight; //當前選中的選項卡索引 private int mSelectedPosition; //選擇位移 private float mSelectionOffset;
2.2 onDraw方法有繪制指示線、底部線、分割線
@Override protected void onDraw(Canvas canvas) { final int height = getHeight(); final int childCount = getChildCount(); final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height); final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null ? mCustomTabColorizer : mDefaultTabColorizer; // Thick colored underline below the current selection if (childCount > 0) { View selectedTitle = getChildAt(mSelectedPosition); int left = selectedTitle.getLeft(); int right = selectedTitle.getRight(); int color = tabColorizer.getIndicatorColor(mSelectedPosition); if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); if (color != nextColor) { color = blendColors(nextColor, color, mSelectionOffset); } // Draw the selection partway between the tabs View nextTitle = getChildAt(mSelectedPosition + 1); left = (int) (mSelectionOffset * nextTitle.getLeft() + (1.0f - mSelectionOffset) * left); right = (int) (mSelectionOffset * nextTitle.getRight() + (1.0f - mSelectionOffset) * right); } mSelectedIndicatorPaint.setColor(color); //繪制指示線 canvas.drawRect(left, height - mSelectedIndicatorThickness, right, height, mSelectedIndicatorPaint); } // 繪制底部線 canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); // 繪制分割線 int separatorTop = (height - dividerHeightPx) / 2; for (int i = 0; i < childCount - 1; i++) { View child = getChildAt(i); mDividerPaint.setColor(tabColorizer.getDividerColor(i)); canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, mDividerPaint); } }
自己做的一個demo,效果圖如下:

並貼上相關代碼:
MainActivity:
package com.jihan.ccimage.activity; import android.content.res.Resources; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.jihan.ccimage.view.slidingTab.SlidingTabLayout; /** * 主類 * Created by :Jihan * on 16/1/14 23:18 */ public class MainActivity extends BaseActivity { private SectionsPagerAdapter mSectionsPagerAdapter; private ViewPager mViewPager; private SlidingTabLayout slidingTabLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //viewPager的內容 mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); //init viewPager mViewPager = (ViewPager) findViewById(R.id.container); mViewPager.setAdapter(mSectionsPagerAdapter); //init slidingTabLayout slidingTabLayout = (SlidingTabLayout)findViewById(R.id.slidingTab); slidingTabLayout.setSelectedIndicatorColors(getResources().getColor(android.R.color.white)); slidingTabLayout.setViewPager(mViewPager); } /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to * one of the sections/tabs/pages. */ public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { // getItem is called to instantiate the fragment for the given page. // Return a PlaceholderFragment (defined as a static inner class below). return PlaceholderFragment.newInstance(position + 1); } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return getResources().getString(R.string.newest); case 1: return getResources().getString(R.string.classify); case 2: return getResources().getString(R.string.ranking); } return null; } } /** * A placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment { /** * The fragment argument representing the section number for this * fragment. */ private static final String ARG_SECTION_NUMBER = "section_number"; /** * Returns a new instance of this fragment for the given section * number. */ public static PlaceholderFragment newInstance(int sectionNumber) { PlaceholderFragment fragment = new PlaceholderFragment(); Bundle args = new Bundle(); args.putInt(ARG_SECTION_NUMBER, sectionNumber); fragment.setArguments(args); return fragment; } public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); TextView textView = (TextView) rootView.findViewById(R.id.section_label); textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER))); return rootView; } } }
SlidingTabLayout.java
package com.jihan.ccimage.view.slidingTab; import android.content.Context; import android.content.res.TypedArray; import android.os.Build; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import android.widget.TextView; import com.jihan.ccimage.activity.R; /** * 引用google的Tab實例源碼(Tab選項卡導航效果) * on 16/1/15 23:56 */ 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 int tabTextSize = 16; //選項卡的高度 private int tabHeight = 40; //是否使用權重 private boolean shouldExpand = true; private int mTitleOffset; private int mTabViewLayoutId; private int mTabViewTextViewId; //選項卡的布局 private LinearLayout.LayoutParams defaultTabLayoutParams; //選項卡的擴展布局 權重為1 private LinearLayout.LayoutParams extendTabLayoutParams; 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); DisplayMetrics dm = getResources().getDisplayMetrics(); mTitleOffset = (int) (TITLE_OFFSET_DIPS * dm.density); tabTextSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm); tabHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabHeight, dm); mTabStrip = new SlidingTabStrip(context); addView(mTabStrip, LayoutParams.MATCH_PARENT, tabHeight); mTabStrip.setBackgroundColor(getResources().getColor(R.color.blue)); //初始化布局 defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); extendTabLayoutParams = new LinearLayout.LayoutParams(0, tabHeight, 1.0f); } /** * 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_PX, tabTextSize); //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 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)); tabTitleView.setTextColor(getResources().getColor(R.color.white)); tabView.setOnClickListener(tabClickListener); mTabStrip.addView(tabView, i, shouldExpand ? extendTabLayoutParams : defaultTabLayoutParams); } } @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 OnClickListener { @Override public void onClick(View v) { for (int i = 0; i < mTabStrip.getChildCount(); i++) { if (v == mTabStrip.getChildAt(i)) { mViewPager.setCurrentItem(i); return; } } } } }
SlidingTabStrip:
/* * 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.jihan.ccimage.view.slidingTab; import android.R; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.LinearLayout; /** * 引用google的Tab實例源碼(Tab選項卡導航效果) * on 16/1/15 23:56 */ class SlidingTabStrip extends LinearLayout { //選項卡底部下划線的高度常量,高度不要超過下划線高度,不然會覆蓋 private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; //選項卡指示下划線的高度常量 private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3; private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; //private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f; //底部下划線 private final int mBottomBorderThickness; private final Paint mBottomBorderPaint; //指示下划線高度 private final int mSelectedIndicatorThickness; private final Paint mSelectedIndicatorPaint; private final int mDefaultBottomBorderColor; private final Paint mDividerPaint; //private final float mDividerHeight; private int mSelectedPosition; private float mSelectionOffset; private SlidingTabLayout.TabColorizer mCustomTabColorizer; private final SimpleTabColorizer mDefaultTabColorizer; SlidingTabStrip(Context context) { this(context, null); } SlidingTabStrip(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); final float density = getResources().getDisplayMetrics().density; TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true); final int themeForegroundColor = outValue.data; mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); mDefaultTabColorizer = new SimpleTabColorizer(); mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR); //mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA)); mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); mBottomBorderPaint = new Paint(); mBottomBorderPaint.setColor(getResources().getColor(com.jihan.ccimage.activity.R.color.blue)); mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); mSelectedIndicatorPaint = new Paint(); //mDividerHeight = DEFAULT_DIVIDER_HEIGHT; mDividerPaint = new Paint(); mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density)); } void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) { mCustomTabColorizer = customTabColorizer; invalidate(); } void setSelectedIndicatorColors(int... colors) { // Make sure that the custom colorizer is removed mCustomTabColorizer = null; mDefaultTabColorizer.setIndicatorColors(colors); invalidate(); } void setDividerColors(int... colors) { // Make sure that the custom colorizer is removed mCustomTabColorizer = null; mDefaultTabColorizer.setDividerColors(colors); invalidate(); } void onViewPagerPageChanged(int position, float positionOffset) { mSelectedPosition = position; mSelectionOffset = positionOffset; invalidate(); } @Override protected void onDraw(Canvas canvas) { final int height = getHeight(); final int childCount = getChildCount(); //final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height); final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null ? mCustomTabColorizer : mDefaultTabColorizer; // Thick colored underline below the current selection if (childCount > 0) { View selectedTitle = getChildAt(mSelectedPosition); int left = selectedTitle.getLeft(); int right = selectedTitle.getRight(); int selectedWidth = selectedTitle.getWidth() / 3 - 30; int color = tabColorizer.getIndicatorColor(mSelectedPosition); if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); if (color != nextColor) { color = blendColors(nextColor, color, mSelectionOffset); } // Draw the selection partway between the tabs View nextTitle = getChildAt(mSelectedPosition + 1); left = (int) (mSelectionOffset * nextTitle.getLeft() + (1.0f - mSelectionOffset) * left); right = (int) (mSelectionOffset * nextTitle.getRight() + (1.0f - mSelectionOffset) * right); } mSelectedIndicatorPaint.setColor(color); canvas.drawRect(left + selectedWidth, height - mSelectedIndicatorThickness, right - selectedWidth, height, mSelectedIndicatorPaint); } // Thin underline along the entire bottom edge 底部線條 canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); // Vertical separators between the titles //設置分割線 /** int separatorTop = (height - dividerHeightPx) / 2; for (int i = 0; i < childCount - 1; i++) { View child = getChildAt(i); mDividerPaint.setColor(tabColorizer.getDividerColor(i)); canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, mDividerPaint); }*/ } /** * Set the alpha value of the {@code color} to be the given {@code alpha} value. */ private static int setColorAlpha(int color, byte alpha) { return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); } /** * Blend {@code color1} and {@code color2} using the given ratio. * * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, * 0.0 will return {@code color2}. */ private static int blendColors(int color1, int color2, float ratio) { final float inverseRation = 1f - ratio; float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); return Color.rgb((int) r, (int) g, (int) b); } private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer { private int[] mIndicatorColors; private int[] mDividerColors; @Override public final int getIndicatorColor(int position) { return mIndicatorColors[position % mIndicatorColors.length]; } @Override public final int getDividerColor(int position) { return mDividerColors[position % mDividerColors.length]; } void setIndicatorColors(int... colors) { mIndicatorColors = colors; } void setDividerColors(int... colors) { mDividerColors = colors; } } }