最近為了滿足公司ui的要求饱苟,TabLayout已經(jīng)滿足不了孩擂,自定義View實現(xiàn)!話不多說直接上代碼
1> TabLayoutView這個是最核心的view
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import com.zcedu.zhuchengjiaoyu.R;
/**
* 自定義控件實現(xiàn) TabLayout效果
*/
public class TabLayoutView extends RelativeLayout {
private static final String TAG = "TabLayoutView";
private HorizontalScrollView hs_indicator;
private RadioGroup rg_indicator;
private View iv_indicator, relativeLayout_indicator;//滑塊,整個容器
private Context mContext;
/**
* radioButton 狀態(tài)顏色選擇集合
**/
private ColorStateList colorStateList;
//新的屬性
private int tabWidth, tabWidthInit;
private int tabTextSize;
private int tabIndicatorColor;
private int tabIndicatorHeight;
private int tabIndicatorWidth;
private ViewPager viewPager;
private int tabPadding, tabIndicatorMarginBottom, stopTablNumber = -1;
private View view;
public TabLayoutView(Context context) {
super(context);
init(context, null, 0, 0);
}
public TabLayoutView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
}
public TabLayoutView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TabLayoutView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, 0);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mContext = context;
TypedArray array = mContext.getTheme().obtainStyledAttributes(new int[]{
android.R.attr.colorPrimary,
android.R.attr.colorPrimaryDark,
android.R.attr.colorAccent,
});
int colorPrimary = array.getColor(0, 0);
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TabLayoutView, defStyleAttr, defStyleRes);
//tabItem的屬性初始化
tabWidthInit = typedArray.getDimensionPixelSize(R.styleable.TabLayoutView_tabWidth, 0);//tab寬度箱熬,不設(shè)置就是wrap_content
tabTextSize = typedArray.getDimensionPixelSize(R.styleable.TabLayoutView_tabTextSize, sp2px(mContext, 15f));//tab字體大小,默認(rèn)15sp
tabTextSize = px2sp(mContext, tabTextSize);
int tabTextColor = typedArray.getColor(R.styleable.TabLayoutView_tabTextColor, Color.BLACK);//tab顏色
int tabSelectedTextColor = typedArray.getColor(R.styleable.TabLayoutView_tabSelectedTextColor, colorPrimary);//tab選中的顏色
colorStateList = createColorStateList(tabSelectedTextColor, tabTextColor);
//tabIndicator的屬性初始化
tabIndicatorColor = typedArray.getColor(R.styleable.TabLayoutView_tabIndicatorColor, colorPrimary);//滑塊的顏色
tabIndicatorHeight = typedArray.getDimensionPixelSize(R.styleable.TabLayoutView_tabIndicatorHeight, 3);//滑塊的高度
tabIndicatorWidth = typedArray.getDimensionPixelSize(R.styleable.TabLayoutView_tabIndicatorWidth, 0);//滑塊的寬度肋殴,不傳就和tab一樣寬
tabPadding = typedArray.getDimensionPixelSize(R.styleable.TabLayoutView_tabPadding, dip2px(mContext, 26f));//如果tab沒有設(shè)置Padding,默認(rèn)26dp
tabIndicatorMarginBottom = typedArray.getDimensionPixelSize(R.styleable.TabLayoutView_tabIndicatorMarginBottom, dip2px(mContext, 4f));//如果滑塊沒有設(shè)置MarginBottom坦弟,默認(rèn)4dp
typedArray.recycle();
//把我們的布局添加到當(dāng)前控件中
view = View.inflate(context, R.layout.item_tab_radiogroup, null);
hs_indicator = (HorizontalScrollView) view.findViewById(R.id.hs_indicator);
rg_indicator = (RadioGroup) view.findViewById(R.id.rg_indicator);
iv_indicator = view.findViewById(R.id.iv_indicator);
relativeLayout_indicator = view.findViewById(R.id.relativeLayout_indicator);
addView(view);
rg_indicator.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (rg_indicator.getChildAt(checkedId) != null) {
RadioButton radioButton1 = (RadioButton) rg_indicator
.getChildAt(checkedId);
Resources resources = mContext.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
int width = dm.widthPixels;//獲取屏幕寬度
stopTablNumber = (stopTablNumber == -1) ? ((width / tabWidth / 2)) : stopTablNumber;//0表示停留在第一個 1就是第二個.... (默認(rèn)停留中間)
RadioButton radioButton2 = (RadioButton) rg_indicator
.getChildAt(stopTablNumber);
if (radioButton1 != null && radioButton2 != null) {
hs_indicator.smoothScrollTo(
(checkedId > stopTablNumber ? radioButton1.getLeft() : 0)
- radioButton2.getLeft(), 0);
if (viewPager != null) {
viewPager.setCurrentItem(checkedId);
}
}
}
}
});
}
/**
* 重新計算繪制后的高度
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
view.setLayoutParams(new RelativeLayout.LayoutParams(widthMeasureSpec, heightMeasureSpec));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
postInvalidate();
}
/**
* 設(shè)置tab停留的位置(默認(rèn)停留在中間)
*
* @param stopTablNumber
*/
public void setStopTablNumber(int stopTablNumber) {
this.stopTablNumber = stopTablNumber;
}
/**
* convert px to its equivalent sp
* <p>
* 將px轉(zhuǎn)換為sp
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* convert sp to its equivalent px
* <p>
* 將sp轉(zhuǎn)換為px
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* 對TextView設(shè)置不同狀態(tài)時其文字顯示顏色
*/
private ColorStateList createColorStateList(int check, int normal) {
int[] colors = new int[]{check, normal};
int[][] states = new int[2][];
states[0] = new int[]{android.R.attr.state_checked};
states[1] = new int[]{};
ColorStateList colorList = new ColorStateList(states, colors);
return colorList;
}
/**
* 讓我們的自定義控件和viewpager相關(guān)聯(lián)
*/
public void setupWithViewPager(@Nullable ViewPager viewPager) {
this.viewPager = viewPager;
PagerAdapter pagerAdapter = viewPager.getAdapter();
rg_indicator.removeAllViews();
for (int position = 0; position < pagerAdapter.getCount(); position++) {
RadioButton rb = new RadioButton(mContext);
rb.setText(pagerAdapter.getPageTitle(position));
rb.setId(position);
int content = tabWidthInit == 0 ? RadioGroup.LayoutParams.WRAP_CONTENT : tabWidthInit;//判斷是否有設(shè)置护锤,沒有就是wrap_content
RadioGroup.LayoutParams layoutParam = new RadioGroup.LayoutParams(
new RadioGroup.LayoutParams(content, RadioGroup.LayoutParams.MATCH_PARENT));
rb.setLayoutParams(layoutParam);
rb.setTextSize(tabTextSize);
rb.setTextColor(colorStateList);
rb.setGravity(Gravity.CENTER_VERTICAL);
rb.setBackgroundColor(Color.TRANSPARENT);
rb.setButtonDrawable(android.R.color.transparent);
//設(shè)置padding
rb.setPadding(tabPadding, 0, tabPadding, 0);
rb.setTag(tabPadding);
if (position == 0) {//默認(rèn)選中第一個
rb.setChecked(true);
}
rg_indicator.addView(rb);
}
Resources resources = mContext.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
int width = dm.widthPixels;//獲取屏幕寬度
if (relativeLayout_indicator.getWidth() < width) {//讓寬度沒有占滿屏幕居中
FrameLayout.LayoutParams layoutParam2 = new FrameLayout.LayoutParams(width, LayoutParams.MATCH_PARENT);
relativeLayout_indicator.setLayoutParams(layoutParam2);
}
getAlbum(0);//滑塊默認(rèn)是第一個RadioButton的寬度
// setCurrentSelectItem(0);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
setCurrentSelectItem(position);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
int s = 0;
LayoutParams layoutParams = (LayoutParams) iv_indicator.getLayoutParams();
for (int i = 0; i < arg0; i++) {
s += rg_indicator.getChildAt(i).getWidth();
}
int width = rg_indicator.getChildAt(arg0).getWidth();
if (arg1 == 0f) { // 停止?jié)L動
layoutParams.setMargins(s + tabPadding, 0, 0, tabIndicatorMarginBottom);
} else {
layoutParams.setMargins((int) (s + (width * arg1)) + tabPadding, 0, 0, tabIndicatorMarginBottom);
}
iv_indicator.setLayoutParams(layoutParams);
}
@Override
public void onPageScrollStateChanged(int position) {
}
});
}
/**
* 根據(jù)手機的分辨率從 dp 的單位 轉(zhuǎn)成為 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根據(jù)RadioButton 動態(tài)計算滑塊的寬度
*
* @param position
*/
public void getAlbum(int position) {
RadioButton rb = (RadioButton) rg_indicator.getChildAt(position);
if (rb == null) {
return;
}
//獲取字的寬度
CharSequence text = rb.getText();
TextPaint paint = rb.getPaint();
int tabWidth2 = (int) (paint.measureText((String) text) + 0.5);
tabWidth = tabWidth2 + 2 * tabPadding;
LayoutParams indicator_LayoutParams = (LayoutParams) iv_indicator.getLayoutParams();
indicator_LayoutParams.height = tabIndicatorHeight;//設(shè)置滑塊的高度
indicator_LayoutParams.width = tabIndicatorWidth == 0 ? tabWidth2 : tabIndicatorWidth;//設(shè)置滑塊的寬度(不傳就和上邊tab一樣長)
indicator_LayoutParams.setMargins(tabPadding, 0, 0, tabIndicatorMarginBottom);//設(shè)置滑塊的Margins 為了和RadioButton對齊
iv_indicator.setLayoutParams(indicator_LayoutParams);
iv_indicator.setBackgroundColor(tabIndicatorColor);//繪制滑塊的顏色
postInvalidate();//重新繪制界面
}
/**
* 設(shè)置當(dāng)前選中條目
*
* @param currentPosition
*/
private void setCurrentSelectItem(int currentPosition) {
getAlbum(currentPosition);//每次滑動就要算滑塊的寬度
RadioButton radioButton = ((RadioButton) rg_indicator
.getChildAt(currentPosition));
if (radioButton != null)
radioButton.performClick();
}
/**
* 設(shè)置當(dāng)前選中條目
*
* @param currentPosition
*/
boolean isSet = false;
public void setCurrent(int currentPosition) {
getAlbum(currentPosition);//每次滑動就要算滑塊的寬度
final RadioButton radioButton = ((RadioButton) rg_indicator
.getChildAt(currentPosition));
if (radioButton != null) {
//view加載完成時回調(diào)
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (!isSet) {
radioButton.performClick();
}
isSet = true;
}
});
}
}
/**
* 獲取當(dāng)前選中條目的position
*
* @return
*/
public int getCurrentSelectPosition() {
int currentIdPosition = rg_indicator.getCheckedRadioButtonId();
return currentIdPosition;
}
}
2> item_tab_radiogroup.xml 由于我不知道代碼怎么貼出來所以只有貼圖了(最外層就一個HorizontalScrollView)
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hs_indicator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<RelativeLayout
android:id="@+id/relativeLayout_indicator"
android:layout_width="wrap_content"
android:layout_height="53dp"
android:gravity="center">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<RadioGroup
android:id="@+id/rg_indicator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal" />
<View
android:id="@+id/iv_indicator"
android:layout_width="50dp"
android:layout_height="0dp"
android:layout_alignParentBottom="true" />
</RelativeLayout>
</RelativeLayout>
</HorizontalScrollView>
attrs.xml的代碼
<declare-styleable name="TabLayoutView">
<attr name="tabTextColor" format="color" />
<attr name="tabSelectedTextColor" format="color" />
<attr name="tabWidth" format="dimension" />
<attr name="tabTextSize" format="dimension" />
<attr name="tabIndicatorColor" format="color" />
<attr name="tabIndicatorHeight" format="dimension" />
<attr name="tabIndicatorWidth" format="dimension" />
<attr name="tabPadding" format="dimension" />
<attr name="tabIndicatorMarginBottom" format="dimension" />
</declare-styleable>
最后附上demo的地址鏈接:https://github.com/haijun0124/TabLayoutView