http://www.oschina.net/code/snippet_731007_24519
Android自定义的TabBar,自定义了几个属性,可以在xml布局文件中使用,Tab的标题、图标等属性可以在布局文件中完成配置,Java代码中只需要指定Tab跳转的监听接口。可以在所有Android版本使用,建议配合ViewPager使用。
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="TabBar"> <attr name="icons" format="reference" /> <!-- icons是一个存放drawable资源文件名的数组 --> <attr name="titles" format="reference" /> <!-- titles是一个存放string的数组 --> <attr name="IconAboveTitle" format="boolean" /> <!-- 允许指定分隔线的drawable --> <attr name="Seperator" format="reference" /> </declare-styleable> </resources>
TabBar.java
package com.pupa.common.widget; import com.pupa.common.util.StringHelper; import com.pupa.TabBarDemo.R; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.Display; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.TextView; public class TabBar extends LinearLayout { private static final String TAG = "TabBar"; private final TabBar mTabBar; // 自己 private final Context mContext; private final AttributeSet mAttrs; private int mDefStyle; private Paint mPaint; private int mCurrentTabMaskColor; private int mCurrentTabMaskAlpha; private String mResPackageName; private CharSequence[] mTitles; private CharSequence[] mIconNames; private Drawable[] mIcons; private Drawable mSeperator; private int mSeperatorResId; private int mSeperatorWidth; private boolean mIconAboveTitle; private int mCurrentTabIndex; private int mTabCount; private int mTabWidth; private int mPosition; private OnCurrentTabChangedListener mTabChangedListener; public static final int POSITION_TOP = 1; // 位于顶部或者底部 public static final int POSITION_BOTTOM = 2; public TabBar(Context context) { this(context, null); // TODO Auto-generated constructor stub } public TabBar(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); // 重要!!! mContext = context; mAttrs = attrs; mCurrentTabIndex = -1; mTabCount = 0; mSeperatorWidth = 0; mPosition = POSITION_TOP; mCurrentTabMaskColor = Color.BLACK; mCurrentTabMaskAlpha = 0x5f; mPaint = new Paint(); mTabBar = this; init(); // TODO Auto-generated constructor stub } @SuppressWarnings("deprecation") public void init() { getResourcesFromXml(); this.setOrientation(LinearLayout.HORIZONTAL); this.setPadding(0, 0, 0, 0); WindowManager wm = (WindowManager) mContext .getSystemService(Context.WINDOW_SERVICE); Display dp = wm.getDefaultDisplay(); mTabWidth = dp.getWidth(); mTabCount = mTitles.length; if (mTabCount > 0) { if (mSeperator != null) { Bitmap bmp = BitmapFactory.decodeResource(getResources(), mSeperatorResId); mSeperatorWidth = bmp.getWidth(); mTabWidth = mTabWidth - (mTabCount - 1) * mSeperatorWidth; bmp.recycle(); bmp = null; } mTabWidth = mTabWidth / mTabCount; // 计算每个tab的宽度 mCurrentTabIndex = 0; } LayoutParams inParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); LayoutParams outParams = new LayoutParams(mTabWidth, LayoutParams.WRAP_CONTENT); LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); View.OnClickListener clkListener = new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub int index = (Integer) v.getTag(); if (index != mCurrentTabIndex) { if (mTabChangedListener != null) mTabChangedListener.onCurrentTabChanged(index); mCurrentTabIndex = index; mTabBar.invalidate(); } } }; //逐个添加Tab for (int i = 0; i < mTabCount; ++i) { LinearLayout tab = new LinearLayout(mContext); tab.setOrientation(LinearLayout.VERTICAL); tab.setPadding(0, 0, 0, 0); tab.setTag(i); // 设置内部标号 tab.setClickable(true); ImageView imv = new ImageView(mContext); imv.setScaleType(ScaleType.CENTER); if (i < mIcons.length) imv.setImageDrawable(mIcons[i]); TextView tv = new TextView(mContext); tv.setGravity(Gravity.CENTER_HORIZONTAL); tv.setText(mTitles[i]); if (mIconAboveTitle) { // 图标在标题之上 tab.addView(imv, inParams); tab.addView(tv, inParams); } else { // 标题在图标之上 tab.addView(tv, inParams); tab.addView(imv, inParams); } tab.setOnClickListener(clkListener); this.addView(tab, outParams); if (mSeperator != null && i < mTabCount - 1) { ImageView sep = new ImageView(mContext); sep.setImageDrawable(mSeperator); this.addView(sep, params); } } } /** * 设置当前Tab的序号 * * @param index * 你想指定的Tab的序号 */ public void setCurrentTab(int index) { if (index > -1 && index < mTabCount&&index!=mCurrentTabIndex) { mCurrentTabIndex = index; this.invalidate(); if (mTabChangedListener != null) mTabChangedListener.onCurrentTabChanged(mCurrentTabIndex); } } public void setOnCurrentTabChangedListener( OnCurrentTabChangedListener listener) { mTabChangedListener = listener; } /** * 设置TabBar在顶端还是底端.真实位置由你的Activity的布局文件决定,这里仅仅是作一个标识, 根据这个信息可以增加一些自定义的效果 * * @param i * 顶端TabBar.POSITION_TOP或底端TabBar.POSITION_BOTTOM */ public void setTabBarPosition(int i) { mPosition = i; } /** * 设定工程中R.java文件的包名,因为在解析出各个Tab的icon时要用到。如果是默认值则无需指定 * * @param name * R.java文件的包名 */ public void setResourcesPackageName(String name) { mResPackageName = name; } /** * 设置Tab选中后的颜色,默认alpha为0x5f * * @param c * rgb颜色值 */ public void setCurrentTabMaskColor(int rgb) { mCurrentTabMaskColor = rgb; } /** * 设置Tab选中后的颜色.为什么要重载这个方法呢?因为我总是记不住Alpha值0和255谁是全透明, 于是宁愿把ARGB颜色中A跟RGB分开设置。。 * * @param rgb * rgb颜色值 * @param a * alpha值 */ public void setCurrentTabMaskColor(int rgb, int a) { mCurrentTabMaskColor = rgb; mCurrentTabMaskAlpha = a; } /** * 获取Tab个数 * * @return Tab个数 */ public int getTabCount() { return mTabCount; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int h = this.getHeight(); if (mCurrentTabIndex > -1 && mCurrentTabIndex < mTabCount) { int startX = (mTabWidth + mSeperatorWidth) * mCurrentTabIndex; mPaint.setColor(mCurrentTabMaskColor); mPaint.setAlpha(mCurrentTabMaskAlpha); mPaint.setStyle(Paint.Style.FILL); canvas.drawRect(new Rect(startX, 0, startX + mTabWidth, h), mPaint); } } /** * 从布局文件的属性值中解析出各个资源 */ private void getResourcesFromXml() { TypedArray ta = mContext.obtainStyledAttributes(mAttrs, R.styleable.TabBar, 0, 0); mIconNames = ta.getTextArray(R.styleable.TabBar_icons); mTitles = ta.getTextArray(R.styleable.TabBar_titles); mIconAboveTitle = ta .getBoolean(R.styleable.TabBar_IconAboveTitle, true); mSeperator = ta.getDrawable(R.styleable.TabBar_Seperator); mSeperatorResId = ta.getResourceId(R.styleable.TabBar_Seperator, -1); if (!StringHelper.notNullAndNotEmpty(mResPackageName)) mResPackageName = mContext.getPackageName(); if (mTitles == null) { mTitles = new CharSequence[0]; // 避免为null } if (mIconNames == null) { mIconNames = new CharSequence[0]; // 避免为null } Resources res = mContext.getResources(); mIcons = new Drawable[mIconNames.length]; for (int i = 0; i < mIconNames.length; ++i) { int id = res.getIdentifier(mIconNames[i].toString(), "drawable", mResPackageName); if (id != 0) mIcons[i] = res.getDrawable(id); } ta.recycle(); } public interface OnCurrentTabChangedListener { public void onCurrentTabChanged(int index); } }
arrays.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="tab_titles"> <item>Tab1</item> <item>Tab2</item> </string-array> <string-array name="tab_icons"> <item>tab1_icon</item> <item>tab2_icon</item> </string-array> </resources>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:pupa="http://schemas.android.com/apk/res/com.pupa.TabDemo" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <com.pupa.common.widget.TabBar android:id="@+id/MainTabBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:background="@android:drawable/title_bar" pupa:Seperator="@drawable/tab_seperator" pupa:icons="@array/tab_icons" pupa:titles="@array/tab_titles" > </com.pupa.common.widget.TabBar> <android.support.v4.view.ViewPager android:id="@+id/MainViewPager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/MainTabBar" /> </RelativeLayout>