//28版本代码
public class TabLayout extends HorizontalScrollView {
private class SlidingTabIndicator extends LinearLayout {
}
}
复制代码
TabLayout.Tab tab = tabLayout.newTab();
View tabView = new TextView(this);
tabLayout.setCustomView(tabView);
tabLayout.addTab(tab);
复制代码
mTitleList.add("潇湘剑雨");
FragmentManager supportFragmentManager = getSupportFragmentManager();
PagerAdapter myAdapter = new PagerAdapter(supportFragmentManager, mFragments, mTitleList);
tabLayout.setAdapter(myAdapter);
public class PagerAdapter extends FragmentPagerAdapter {
private List<?> mFragment;
private List<String> mTitleList;
public PagerAdapter(FragmentManager fm, List<?> mFragment, List<String> mTitleList) {
super(fm);
this.mFragment = mFragment;
this.mTitleList = mTitleList;
}
@Override
public CharSequence getPageTitle(int position) {
if (mTitleList != null) {
return mTitleList.get(position);
} else {
return "";
}
}
}
复制代码
void populateFromPagerAdapter() {
this.removeAllTabs();
if (this.pagerAdapter != null) {
int adapterCount = this.pagerAdapter.getCount();
int curItem;
for(curItem = 0; curItem < adapterCount; ++curItem) {
this.addTab(this.newTab().setText(this.pagerAdapter.getPageTitle(curItem)), false);
}
if (this.viewPager != null && adapterCount > 0) {
curItem = this.viewPager.getCurrentItem();
if (curItem != this.getSelectedTabPosition() && curItem < this.getTabCount()) {
this.selectTab(this.getTabAt(curItem));
}
}
}
}
复制代码
public void addTab(@NonNull TabLayout.Tab tab, int position, boolean setSelected) {
if (tab.parent != this) {
throw new IllegalArgumentException("Tab belongs to a different TabLayout.");
} else {
this.configureTab(tab, position);
this.addTabView(tab);
if (setSelected) {
tab.select();
}
}
}
private void addTabView(TabLayout.Tab tab) {
TabLayout.TabView tabView = tab.view;
this.slidingTabIndicator.addView(tabView, tab.getPosition(), this.createLayoutParamsForTabs());
}
复制代码
private void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh, boolean implicitSetup) {
if (this.viewPager != null) {
if (this.pageChangeListener != null) {
this.viewPager.removeOnPageChangeListener(this.pageChangeListener);
}
if (this.adapterChangeListener != null) {
this.viewPager.removeOnAdapterChangeListener(this.adapterChangeListener);
}
}
if (this.currentVpSelectedListener != null) {
this.removeOnTabSelectedListener(this.currentVpSelectedListener);
this.currentVpSelectedListener = null;
}
if (viewPager != null) {
this.viewPager = viewPager;
if (this.pageChangeListener == null) {
this.pageChangeListener = new TabLayout.TabLayoutOnPageChangeListener(this);
}
this.pageChangeListener.reset();
viewPager.addOnPageChangeListener(this.pageChangeListener);
this.currentVpSelectedListener = new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
this.addOnTabSelectedListener(this.currentVpSelectedListener);
PagerAdapter adapter = viewPager.getAdapter();
if (adapter != null) {
this.setPagerAdapter(adapter, autoRefresh);
}
if (this.adapterChangeListener == null) {
this.adapterChangeListener = new TabLayout.AdapterChangeListener();
}
this.adapterChangeListener.setAutoRefresh(autoRefresh);
viewPager.addOnAdapterChangeListener(this.adapterChangeListener);
this.setScrollPosition(viewPager.getCurrentItem(), 0.0F, true);
} else {
this.viewPager = null;
this.setPagerAdapter((PagerAdapter)null, false);
}
this.setupViewPagerImplicitly = implicitSetup;
}
复制代码
public static class TabLayoutOnPageChangeListener implements OnPageChangeListener {
public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
this.tabLayoutRef = new WeakReference(tabLayout);
}
public void onPageScrollStateChanged(int state) {
this.previousScrollState = this.scrollState;
this.scrollState = state;
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
TabLayout tabLayout = (TabLayout)this.tabLayoutRef.get();
if (tabLayout != null) {
boolean updateText = this.scrollState != 2 || this.previousScrollState == 1;
boolean updateIndicator = this.scrollState != 2 || this.previousScrollState != 0;
tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
}
}
public void onPageSelected(int position) {
TabLayout tabLayout = (TabLayout)this.tabLayoutRef.get();
if (tabLayout != null && tabLayout.getSelectedTabPosition() != position && position < tabLayout.getTabCount()) {
boolean updateIndicator = this.scrollState == 0 || this.scrollState == 2 && this.previousScrollState == 0;
tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
}
}
}
复制代码
private void updateIndicatorPosition() {
//根据当前滑块的位置拿到当前TabView
View selectedTitle = this.getChildAt(this.selectedPosition);
int left;
int right;
if (selectedTitle != null && selectedTitle.getWidth() > 0) {
//拿到TabView的左、右位置
left = selectedTitle.getLeft();
right = selectedTitle.getRight();
if (!TabLayout.this.tabIndicatorFullWidth && selectedTitle instanceof TabLayout.TabView) {
this.calculateTabViewContentBounds((TabLayout.TabView)selectedTitle, TabLayout.this.tabViewContentBounds);
left = (int)TabLayout.this.tabViewContentBounds.left;
right = (int)TabLayout.this.tabViewContentBounds.right;
}
//在滑块滑动的时候,若是滑动超过了上一个或是下一个滑块一半的话
//那就说明移动到了上一个或是下一个滑块,而后取出left和right
if (this.selectionOffset > 0.0F && this.selectedPosition < this.getChildCount() - 1) {
View nextTitle = this.getChildAt(this.selectedPosition + 1);
int nextTitleLeft = nextTitle.getLeft();
int nextTitleRight = nextTitle.getRight();
if (!TabLayout.this.tabIndicatorFullWidth && nextTitle instanceof TabLayout.TabView) {
this.calculateTabViewContentBounds((TabLayout.TabView)nextTitle, TabLayout.this.tabViewContentBounds);
nextTitleLeft = (int)TabLayout.this.tabViewContentBounds.left;
nextTitleRight = (int)TabLayout.this.tabViewContentBounds.right;
}
left = (int)(this.selectionOffset * (float)nextTitleLeft + (1.0F - this.selectionOffset) * (float)left);
right = (int)(this.selectionOffset * (float)nextTitleRight + (1.0F - this.selectionOffset) * (float)right);
}
} else {
right = -1;
left = -1;
}
//设置滑块的位置
this.setIndicatorPosition(left, right);
}
复制代码
void setIndicatorPosition(int left, int right) {
if (left != this.indicatorLeft || right != this.indicatorRight) {
this.indicatorLeft = left;
this.indicatorRight = right;
ViewCompat.postInvalidateOnAnimation(this);
}
}
复制代码
@Override
public void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh) {
super.setupWithViewPager(viewPager, autoRefresh);
try {
//经过反射找到mPageChangeListener
Field field = getPageChangeListener();
field.setAccessible(true);
TabLayoutOnPageChangeListener listener = (TabLayoutOnPageChangeListener) field.get(this);
if (listener!=null && viewPager!=null) {
//删除自带监听
viewPager.removeOnPageChangeListener(listener);
OnPageChangeListener mPageChangeListener = new OnPageChangeListener(this);
mPageChangeListener.reset();
viewPager.addOnPageChangeListener(mPageChangeListener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
/**
* 反射获取私有的mPageChangeListener属性,考虑support 28之后变量名修改的问题
* @return Field
* @throws NoSuchFieldException
*/
private Field getPageChangeListener() throws NoSuchFieldException {
Class clazz = TabLayout.class;
try {
// support design 27及一下版本
return clazz.getDeclaredField("mPageChangeListener");
} catch (NoSuchFieldException e) {
e.printStackTrace();
// 多是28及以上版本
return clazz.getDeclaredField("pageChangeListener");
}
}
复制代码
/**
* 滑动监听,核心逻辑
* 建议若是是activity退到后台,或者关闭页面,将listener给remove掉
* 采用弱引用方式防止监听listener内存泄漏,算是一个小的优化
*/
private static class OnPageChangeListener extends TabLayoutOnPageChangeListener {
private final WeakReference<CustomTabLayout> mTabLayoutRef;
private int mPreviousScrollState;
private int mScrollState;
OnPageChangeListener(TabLayout tabLayout) {
super(tabLayout);
mTabLayoutRef = new WeakReference<>((CustomTabLayout) tabLayout);
}
/**
* 这个方法是滚动状态发生变化是调用
* @param state 桩体
*/
@Override
public void onPageScrollStateChanged(final int state) {
mPreviousScrollState = mScrollState;
mScrollState = state;
}
/**
* 正在滚动时调用
* @param position 索引
* @param positionOffset offset偏移
* @param positionOffsetPixels offsetPixels
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
CustomTabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout == null) {
return;
}
final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
mPreviousScrollState == SCROLL_STATE_DRAGGING;
if (updateText) {
tabLayout.tabScrolled(position, positionOffset);
}
}
/**
* 选中时调用
* @param position 索引
*/
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
CustomTabLayout tabLayout = mTabLayoutRef.get();
mPreviousScrollState = SCROLL_STATE_SETTLING;
tabLayout.setSelectedView(position);
}
/**
* 重置状态
*/
void reset() {
mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
}
}
复制代码
/**
* 经过反射设置TabLayout每个的长度
* @param left 左边 Margin 单位 dp
* @param right 右边 Margin 单位 dp
*/
public void setIndicator(int left, int right) {
Field tabStrip = null;
try {
tabStrip = getTabStrip();
tabStrip.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
LinearLayout llTab = null;
try {
if (tabStrip != null) {
llTab = (LinearLayout) tabStrip.get(this);
}
} catch (Exception e) {
e.printStackTrace();
}
int l = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, left,
Resources.getSystem().getDisplayMetrics());
int r = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, right,
Resources.getSystem().getDisplayMetrics());
if (llTab != null) {
for (int i = 0; i < llTab.getChildCount(); i++) {
View child = llTab.getChildAt(i);
child.setPadding(0, 0, 0, 0);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
params.leftMargin = l;
params.rightMargin = r;
child.setLayoutParams(params);
child.invalidate();
}
}
}
复制代码
/**
* 反射获取私有的mTabStrip属性,考虑support 28之后变量名修改的问题
* @return Field
* @throws NoSuchFieldException
*/
private Field getTabStrip() throws NoSuchFieldException {
Class clazz = TabLayout.class;
try {
// support design 27及一下版本
return clazz.getDeclaredField("mTabStrip");
} catch (NoSuchFieldException e) {
e.printStackTrace();
// 多是28及以上版本
return clazz.getDeclaredField("slidingTabIndicator");
}
}
复制代码
public void setTabWidth(TabLayout tabLayout){
//拿到slidingTabIndicator的布局
LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0);
//遍历SlidingTabStrip的全部TabView子view
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
View tabView = mTabStrip.getChildAt(i);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)tabView.getLayoutParams();
//给TabView设置leftMargin和rightMargin
params.leftMargin = dp2px(10);
params.rightMargin = dp2px(10);
tabView.setLayoutParams(params);
//触发绘制
tabView.invalidate();
}
}
复制代码
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
CustomTabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout == null) {
return;
}
final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
mPreviousScrollState == SCROLL_STATE_DRAGGING;
if (updateText) {
tabLayout.tabScrolled(position, positionOffset);
}
}
复制代码
/**
* 滑动改变自定义tabView的颜色
* @param position 索引
* @param positionOffset 偏移量
*/
private void tabScrolled(int position, float positionOffset) {
if (positionOffset == 0.0F) {
return;
}
//当前tabView
CustomTabView currentTrackView = getCustomTabView(position);
//下一个tabView
CustomTabView nextTrackView = getCustomTabView(position + 1);
if (currentTrackView != null) {
currentTrackView.setDirection(1);
currentTrackView.setProgress(1.0F - positionOffset);
}
if (nextTrackView != null) {
nextTrackView.setDirection(0);
nextTrackView.setProgress(positionOffset);
}
}
复制代码
public void setProgress(float progress) {
this.mProgress = progress;
invalidate();
}
复制代码
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDirection == DIRECTION_LEFT) {
drawChangeLeft(canvas);
drawOriginLeft(canvas);
} else if (mDirection == DIRECTION_RIGHT) {
drawOriginRight(canvas);
drawChangeRight(canvas);
} else if (mDirection == DIRECTION_TOP) {
drawOriginTop(canvas);
drawChangeTop(canvas);
} else if (mDirection == DIRECTION_BOTTOM){
drawOriginBottom(canvas);
drawChangeBottom(canvas);
}
}
复制代码
private void drawChangeLeft(Canvas canvas) {
drawTextHor(canvas, mTextChangeColor, mTextStartX, (int) (mTextStartX + mProgress * mTextWidth));
}
/**
* 横向
* @param canvas 画板
* @param color 颜色
* @param startX 开始x
* @param endX 结束x
*/
private void drawTextHor(Canvas canvas, int color, int startX, int endX) {
mPaint.setColor(color);
if (debug) {
mPaint.setStyle(Style.STROKE);
canvas.drawRect(startX, 0, endX, getMeasuredHeight(), mPaint);
}
canvas.save();
canvas.clipRect(startX, 0, endX, getMeasuredHeight());
// right, bottom
canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2
- ((mPaint.descent() + mPaint.ascent()) / 2), mPaint);
canvas.restore();
}
复制代码
/**
* 反射获取私有的mTabStrip属性,考虑support 28之后变量名修改的问题
* @return Field
* @throws NoSuchFieldException
*/
private Field getTabStrip() throws NoSuchFieldException {
Class clazz = TabLayout.class;
try {
// support design 27及一下版本
return clazz.getDeclaredField("mTabStrip");
} catch (NoSuchFieldException e) {
e.printStackTrace();
// 多是28及以上版本
return clazz.getDeclaredField("slidingTabIndicator");
}
}
复制代码
-keep class android.support.design.widget.TabLayout{*;}
复制代码