选项卡导航开发viewpager + SlidingTabsLayout及SlidingTabsLayout的用法
从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; } } }