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

2024-06-06 03:18

本文主要是介绍【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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1034943

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目