本文主要是介绍【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/
这篇关于【Android源代码】Android自定义的TabBar的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!