【Android源代码】Android自定义的TabBar

(更多Android开发源码请访问:eoe移动开发者社区 http://www.eoeandroid.com/

Android自定义的TabBar,自定义了几个属性,可以在xml布局文件中使用,Tab的标题、图标等属性可以在布局文件中完成配置,Java代码中只需要指定Tab跳转的监听接口。可以在所有Android版本使用,建议配合ViewPager使用。
完整的Demo工程已给出!

 

1. [文件]     attrs.xml ~ 520B    

01 <?xml version=“1.0” encoding=“utf-8”?> 
02 <resources> 
03     <declare-styleable name=“TabBar”> 
04         <attr name=“icons” format=“reference” /> 
05         <!-- icons是一个存放drawable资源文件名的数组 --> 
06         <attr name=“titles” format=“reference” /> 
07         <!-- titles是一个存放string的数组 --> 
08         <attr name=“IconAboveTitle” format=“boolean” /> 
09         <!-- 允许指定分隔线的drawable --> 
10         <attr name=“Seperator” format=“reference” /> 
11     </declare-styleable>  
12 </resources> 

2. [文件]     TabBar.java ~ 8KB    

001 package com.pupa.common.widget; 
002   
003 import com.pupa.common.util.StringHelper; 
004 import com.pupa.TabBarDemo.R; 
005   
006 import android.annotation.SuppressLint; 
007 import android.content.Context; 
008 import android.content.res.Resources; 
009 import android.content.res.TypedArray; 
010 import android.graphics.Bitmap; 
011 import android.graphics.BitmapFactory; 
012 import android.graphics.Canvas; 
013 import android.graphics.Color; 
014 import android.graphics.Paint; 
015 import android.graphics.Rect; 
016 import android.graphics.drawable.Drawable; 
017 import android.util.AttributeSet; 
018 import android.view.Display; 
019 import android.view.Gravity; 
020 import android.view.View; 
021 import android.view.WindowManager; 
022 import android.widget.ImageView; 
023 import android.widget.ImageView.ScaleType; 
024 import android.widget.LinearLayout; 
025 import android.widget.TextView; 
026   
027 public class TabBar extends LinearLayout { 
028     private static final String TAG = “TabBar”; 
029     private final TabBar mTabBar; // 自己 
030     private final Context mContext; 
031     private final AttributeSet mAttrs; 
032     private int mDefStyle; 
033   
034     private Paint mPaint; 
035     private int mCurrentTabMaskColor; 
036     private int mCurrentTabMaskAlpha; 
037   
038     private String mResPackageName; 
039     private CharSequence[] mTitles; 
040     private CharSequence[] mIconNames; 
041     private Drawable[] mIcons; 
042     private Drawable mSeperator; 
043     private int mSeperatorResId; 
044     private int mSeperatorWidth; 
045   
046     private boolean mIconAboveTitle; 
047   
048     private int mCurrentTabIndex; 
049     private int mTabCount; 
050     private int mTabWidth; 
051     private int mPosition; 
052     private OnCurrentTabChangedListener mTabChangedListener; 
053   
054     public static final int POSITION_TOP = 1; // 位于顶部或者底部 
055     public static final int POSITION_BOTTOM = 2; 
056   
057     public TabBar(Context context) { 
058         this(context, null); 
059         // TODO Auto-generated constructor stub 
060     } 
061   
062     public TabBar(Context context, AttributeSet attrs) { 
063         super(context, attrs); 
064         setWillNotDraw(false); // 重要!!! 
065         mContext = context; 
066         mAttrs = attrs; 
067         mCurrentTabIndex = -1; 
068         mTabCount = 0; 
069         mSeperatorWidth = 0; 
070         mPosition = POSITION_TOP; 
071         mCurrentTabMaskColor = Color.BLACK; 
072         mCurrentTabMaskAlpha = 0x5f; 
073         mPaint = new Paint(); 
074         mTabBar = this; 
075         init(); 
076         // TODO Auto-generated constructor stub 
077     } 
078       
079     @SuppressWarnings(“deprecation”) 
080     public void init() { 
081         getResourcesFromXml(); 
082         this.setOrientation(LinearLayout.HORIZONTAL); 
083         this.setPadding(0, 0, 0, 0); 
084   
085         WindowManager wm = (WindowManager) mContext 
086                 .getSystemService(Context.WINDOW_SERVICE); 
087         Display dp = wm.getDefaultDisplay(); 
088         mTabWidth = dp.getWidth(); 
089   
090         mTabCount = mTitles.length; 
091   
092         if (mTabCount > 0) { 
093             if (mSeperator != null) { 
094                 Bitmap bmp = BitmapFactory.decodeResource(getResources(), 
095                         mSeperatorResId); 
096                 mSeperatorWidth = bmp.getWidth(); 
097                 mTabWidth = mTabWidth - (mTabCount - 1) * mSeperatorWidth; 
098                 bmp.recycle(); 
099                 bmp = null; 
100             } 
101             mTabWidth = mTabWidth / mTabCount; // 计算每个tab的宽度 
102             mCurrentTabIndex = 0; 
103         } 
104   
105         LayoutParams inParams = new LayoutParams(LayoutParams.MATCH_PARENT, 
106                 LayoutParams.WRAP_CONTENT); 
107         LayoutParams outParams = new LayoutParams(mTabWidth, 
108                 LayoutParams.WRAP_CONTENT); 
109         LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, 
110                 LayoutParams.WRAP_CONTENT); 
111         View.OnClickListener clkListener = new View.OnClickListener() { 
112   
113             @Override 
114             public void onClick(View v) { 
115                 // TODO Auto-generated method stub 
116                 int index = (Integer) v.getTag(); 
117                 if (index != mCurrentTabIndex) { 
118                     if (mTabChangedListener != null) 
119                         mTabChangedListener.onCurrentTabChanged(index); 
120                     mCurrentTabIndex = index; 
121                     mTabBar.invalidate(); 
122                 } 
123             } 
124         }; 
125           
126         //逐个添加Tab 
127         for (int i = 0; i < mTabCount; ++i) { 
128             LinearLayout tab = new LinearLayout(mContext); 
129             tab.setOrientation(LinearLayout.VERTICAL); 
130             tab.setPadding(0, 0, 0, 0); 
131             tab.setTag(i); // 设置内部标号 
132             tab.setClickable(true); 
133             ImageView imv = new ImageView(mContext); 
134             imv.setScaleType(ScaleType.CENTER); 
135             if (i < mIcons.length) 
136                 imv.setImageDrawable(mIcons[i]); 
137             TextView tv = new TextView(mContext); 
138             tv.setGravity(Gravity.CENTER_HORIZONTAL); 
139             tv.setText(mTitles[i]); 
140             if (mIconAboveTitle) { // 图标在标题之上 
141                 tab.addView(imv, inParams); 
142                 tab.addView(tv, inParams); 
143             } else { // 标题在图标之上 
144                 tab.addView(tv, inParams); 
145                 tab.addView(imv, inParams); 
146             } 
147             tab.setOnClickListener(clkListener); 
148             this.addView(tab, outParams); 
149             if (mSeperator != null && i < mTabCount - 1) { 
150                 ImageView sep = new ImageView(mContext); 
151                 sep.setImageDrawable(mSeperator); 
152                 this.addView(sep, params); 
153             } 
154         } 
155     } 
156   
157     /** 
158      * 设置当前Tab的序号 
159      *  
160      * @param index 
161      *            你想指定的Tab的序号 
162      */ 
163     public void setCurrentTab(int index) { 
164         if (index > -1 && index < mTabCount&&index!=mCurrentTabIndex) { 
165             mCurrentTabIndex = index; 
166             this.invalidate(); 
167             if (mTabChangedListener != null) 
168                 mTabChangedListener.onCurrentTabChanged(mCurrentTabIndex); 
169         } 
170     } 
171   
172     public void setOnCurrentTabChangedListener( 
173             OnCurrentTabChangedListener listener) { 
174         mTabChangedListener = listener; 
175     } 
176   
177     /** 
178      * 设置TabBar在顶端还是底端。真实位置由你的Activity的布局文件决定,这里仅仅是作一个标识, 根据这个信息可以增加一些自定义的效果 
179      *  
180      * @param i 
181      *            顶端TabBar.POSITION_TOP或底端TabBar.POSITION_BOTTOM 
182      */ 
183     public void setTabBarPosition(int i) { 
184         mPosition = i; 
185     } 
186   
187     /** 
188      * 设定工程中R.java文件的包名,因为在解析出各个Tab的icon时要用到。如果是默认值则无需指定 
189      *  
190      * @param name 
191      *            R.java文件的包名 
192      */ 
193     public void setResourcesPackageName(String name) { 
194         mResPackageName = name; 
195     } 
196   
197     /** 
198      * 设置Tab选中后的颜色,默认alpha为0x5f 
199      *  
200      * @param c 
201      *            rgb颜色值 
202      */ 
203     public void setCurrentTabMaskColor(int rgb) { 
204         mCurrentTabMaskColor = rgb; 
205     } 
206   
207     /** 
208      * 设置Tab选中后的颜色。为什么要重载这个方法呢?因为我总是记不住Alpha值0和255谁是全透明, 于是宁愿把ARGB颜色中A跟RGB分开设置…… 
209      *  
210      * @param rgb 
211      *            rgb颜色值 
212      * @param a 
213      *            alpha值 
214      */ 
215     public void setCurrentTabMaskColor(int rgb, int a) { 
216         mCurrentTabMaskColor = rgb; 
217         mCurrentTabMaskAlpha = a; 
218     } 
219   
220     /** 
221      * 获取Tab个数 
222      *  
223      * @return Tab个数 
224      */ 
225     public int getTabCount() { 
226         return mTabCount; 
227     } 
228   
229     @Override 
230     protected void onDraw(Canvas canvas) { 
231         super.onDraw(canvas); 
232         int h = this.getHeight(); 
233         if (mCurrentTabIndex > -1 && mCurrentTabIndex < mTabCount) { 
234             int startX = (mTabWidth + mSeperatorWidth) * mCurrentTabIndex; 
235             mPaint.setColor(mCurrentTabMaskColor); 
236             mPaint.setAlpha(mCurrentTabMaskAlpha); 
237             mPaint.setStyle(Paint.Style.FILL); 
238             canvas.drawRect(new Rect(startX, 0, startX + mTabWidth, h), mPaint); 
239         } 
240     } 
241   
242     /** 
243      * 从布局文件的属性值中解析出各个资源 
244      */ 
245     private void getResourcesFromXml() { 
246         TypedArray ta = mContext.obtainStyledAttributes(mAttrs, 
247                 R.styleable.TabBar, 0, 0); 
248         mIconNames = ta.getTextArray(R.styleable.TabBar_icons); 
249         mTitles = ta.getTextArray(R.styleable.TabBar_titles); 
250         mIconAboveTitle = ta 
251                 .getBoolean(R.styleable.TabBar_IconAboveTitle, true); 
252         mSeperator = ta.getDrawable(R.styleable.TabBar_Seperator); 
253         mSeperatorResId = ta.getResourceId(R.styleable.TabBar_Seperator, -1); 
254   
255         if (!StringHelper.notNullAndNotEmpty(mResPackageName)) 
256             mResPackageName = mContext.getPackageName(); 
257   
258         if (mTitles == null) { 
259             mTitles = new CharSequence[0]; // 避免为null 
260         } 
261   
262         if (mIconNames == null) { 
263             mIconNames = new CharSequence[0]; // 避免为null 
264         } 
265   
266         Resources res = mContext.getResources(); 
267         mIcons = new Drawable[mIconNames.length]; 
268         for (int i = 0; i < mIconNames.length; ++i) { 
269             int id = res.getIdentifier(mIconNames[i].toString(), “drawable”, 
270                     mResPackageName); 
271             if (id != 0) 
272                 mIcons[i] = res.getDrawable(id); 
273         } 
274   
275         ta.recycle(); 
276     } 
277   
278     public interface OnCurrentTabChangedListener { 
279         public void onCurrentTabChanged(int index); 
280     } 
281 } 


3. [文件]     arrays.xml ~ 304B    

 

01 <?xml version=“1.0” encoding=“utf-8”?> 
02 <resources> 
03   
04     <string-array name=“tab_titles”> 
05         <item>Tab1</item> 
06         <item>Tab2</item> 
07     </string-array> 
08     <string-array name=“tab_icons”> 
09         <item>tab1_icon</item> 
10         <item>tab2_icon</item> 
11     </string-array> 
12   
13 </resources> 

4. [文件]     activity_main.xml ~ 1002B

01 <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android” 
02     xmlns:tools=“http://schemas.android.com/tools” 
03     xmlns:pupa=“http://schemas.android.com/apk/res/com.pupa.TabDemo” 
04     android:layout_width=“match_parent” 
05     android:layout_height=“match_parent” 
06     tools:context=“.MainActivity” > 
07   
08     <com.pupa.common.widget.TabBar 
09         android:id=“@+id/MainTabBar” 
10         android:layout_width=“match_parent” 
11         android:layout_height=“wrap_content” 
12         android:layout_alignParentTop=“true” 
13         android:background=“@android:drawable/title_bar” 
14         pupa:Seperator=“@drawable/tab_seperator” 
15         pupa:icons=“@array/tab_icons” 
16         pupa:titles=“@array/tab_titles” > 
17     </com.pupa.common.widget.TabBar> 
18   
19     <android.support.v4.view.ViewPager 
20         android:id=“@+id/MainViewPager” 
21         android:layout_width=“match_parent” 
22         android:layout_height=“match_parent” 
23         android:layout_below=“@id/MainTabBar” /> 
24   
25 </RelativeLayout> 

 

5. [文件]     TabBarDemo.zip ~ 703KB    

    eoe成立于2009年,创办了最早也是目前为止最大的中文移动开发者社区:www.eoe.cn 
超过160万的移动开发者汇聚在eoe,共同讨论最前沿最精彩的技术话题。eoe一直致力于为移动开发者提供全方位的服务。
    更多内容请关注eoe移动开发者社区:
http://www.eoeandroid.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值