//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{*;}
複製代碼