http://blog.csdn.net/zoeice/article/details/8068671

  1. import java.util.Vector;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.Canvas;
  6. import android.graphics.NinePatch;
  7. import android.graphics.Paint;
  8. import android.graphics.Rect;
  9. import android.util.DisplayMetrics;
  10. import android.view.GestureDetector;
  11. import android.view.GestureDetector.OnGestureListener;
  12. import android.view.MotionEvent;
  13. import android.view.View;
  14. import android.view.View.OnTouchListener;
  15. import android.widget.PopupWindow;
  16. import com.example.zoeicetabgroup.R;
  17. /**
  18. * custom tab bar
  19. * @author zoeice
  20. *
  21. */
  22. public class LPTabGroupWithGesture extends View implements OnGestureListener, OnTouchListener{
  23. private int tabNum = 0;
  24. private int curSelect = 0;
  25. private int curX = 0;
  26. private int savedClickIndex = -1;
  27. private int savedX = 0;
  28. private boolean isDraging = false;
  29. private int dragCurrentX = 0;
  30. private int dragSavedX = 0;
  31. private int dragSelectIndex = -1;
  32. private final int TEXT_SIZE = 30;
  33. private final int TAB_MARGIN = 30;
  34. private int tabWidth = 200;
  35. private int tabHeight = 0;
  36. private int tabGap = 30;// IF
  37. private int tabAddWidth = 90;// IF
  38. private Bitmap bitCur;
  39. private NinePatch npCur;
  40. private Bitmap bitNor;
  41. private NinePatch npNor;
  42. private Bitmap bitAdd;
  43. private int screenWidth;
  44. private int screenHeight;
  45. private float screenDensity;
  46. private PopupWindow popMenu;
  47. private OnTabItemClickListener clickListener;
  48. private GestureDetector mGestureDetector;
  49. private Vector<TabItem> tabLists = new Vector<TabItem>();
  50. public LPTabGroupWithGesture(Context context, Vector<TabItem> vec) {
  51. this(context);
  52. tabLists = vec;
  53. tabNum = vec.size();
  54. }
  55. public LPTabGroupWithGesture(Context context) {
  56. super(context);
  57. if(tabNum == 0){
  58. tabNum = 1;
  59. tabLists.add(new TabItem());
  60. }
  61. initParams(context);
  62. }
  63. /**
  64. * init view's params
  65. */
  66. private void initParams(Context context){
  67. this.setLongClickable(true);
  68. this.setOnTouchListener(this);
  69. mGestureDetector = new GestureDetector(context, this);
  70. mGestureDetector.setIsLongpressEnabled(true);
  71. DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
  72. screenWidth = displayMetrics.widthPixels;
  73. screenHeight = displayMetrics.heightPixels;
  74. screenDensity = displayMetrics.density;
  75. bitCur = BitmapFactory.decodeResource(getResources(),
  76. R.drawable.tab);
  77. npCur = new NinePatch(bitCur, bitCur.getNinePatchChunk(), null);
  78. tabHeight = bitCur.getHeight();
  79. bitNor = BitmapFactory.decodeResource(getResources(),
  80. R.drawable.tab);
  81. npNor = new NinePatch(bitNor, bitNor.getNinePatchChunk(), null);
  82. bitAdd = BitmapFactory.decodeResource(getResources(),
  83. R.drawable.tab_add);
  84. tabAddWidth = bitAdd.getWidth();
  85. }
  86. /**设置当前选中选项的位置*/
  87. public void setCurrentSelect(int index) {
  88. curSelect = index;
  89. invalidate();
  90. }
  91. /**
  92. * @see android.view.View#measure(int, int)
  93. */
  94. @Override
  95. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  96. setMeasuredDimension(screenWidth, tabHeight);
  97. }
  98. @Override
  99. protected void onDraw(Canvas canvas) {
  100. super.onDraw(canvas);
  101. Paint paint = new Paint();
  102. paint.setColor(0xff707070);
  103. paint.setTextSize(TEXT_SIZE);
  104. /*draw bg*/
  105. canvas.drawARGB(0xff, 0xa1, 0x9c, 0xff);
  106. if(isDraging){
  107. int dX = dragCurrentX +  (tabWidth - tabGap) * curSelect;
  108. /*draw normal tab*/
  109. for (int i = tabNum - 1; i >= 0; i--) {
  110. if (i != curSelect) {
  111. int nX = curX + (tabWidth - tabGap) * i ;
  112. if(i > savedClickIndex && savedClickIndex > -1){
  113. nX -= tabWidth - tabGap;
  114. }
  115. if(i > dragSelectIndex && dragSelectIndex > -1){
  116. nX += tabWidth - tabGap;
  117. }
  118. Rect nR = new Rect(nX, 0, nX + tabWidth, tabHeight);
  119. npNor.draw(canvas, nR);
  120. //draw text
  121. canvas.save();
  122. canvas.clipRect(new Rect(nX + TAB_MARGIN, 0, nX + tabWidth - TAB_MARGIN, tabHeight));
  123. canvas.drawText(tabLists.get(i).name, nX + TAB_MARGIN, (tabHeight + TEXT_SIZE) >> 1, paint);
  124. canvas.restore();
  125. }
  126. }
  127. /*draw shape for above normal tab*/
  128. canvas.drawARGB(0x50, 0x00, 0x00, 0x00);
  129. /*draw buttom line*/
  130. Paint paintShape = new Paint();
  131. paintShape.setColor(0x50000000);
  132. canvas.drawRect(0, tabHeight - 2, screenWidth, tabHeight, paintShape);
  133. /*draw current selected tab*/
  134. Rect dR = new Rect(dX, 0, dX + tabWidth, tabHeight);
  135. npCur.draw(canvas, dR);
  136. //draw current text
  137. paint.setColor(0xff456789);
  138. canvas.drawText(tabLists.get(curSelect).name, dX + tabGap, (tabHeight + TEXT_SIZE) >> 1, paint);
  139. /*draw add button*/
  140. int aX =  curX + (tabWidth - tabGap) * tabNum;
  141. if(dX + tabWidth > aX)
  142. canvas.drawBitmap(bitAdd, dX + tabWidth - tabGap, 0, paint);
  143. else
  144. canvas.drawBitmap(bitAdd, aX, 0, paint);
  145. }else{
  146. /*draw normal tab*/
  147. for (int i = tabNum - 1; i >= 0; i--) {
  148. if (i != curSelect) {
  149. int nX = curX + (tabWidth - tabGap) * i ;
  150. Rect nR = new Rect(nX, 0, nX + tabWidth, tabHeight);
  151. npNor.draw(canvas, nR);
  152. //draw text
  153. canvas.save();
  154. canvas.clipRect(new Rect(nX + TAB_MARGIN, 0, nX + tabWidth - TAB_MARGIN, tabHeight));
  155. canvas.drawText(tabLists.get(i).name, nX + TAB_MARGIN, (tabHeight + TEXT_SIZE) >> 1, paint);
  156. canvas.restore();
  157. }
  158. }
  159. /*draw shape for above normal tab*/
  160. canvas.drawARGB(0x50, 0x00, 0x00, 0x00);
  161. /*draw buttom line*/
  162. Paint paintShape = new Paint();
  163. paintShape.setColor(0x50000000);
  164. canvas.drawRect(0, tabHeight - 2, screenWidth, tabHeight, paintShape);
  165. /*draw current selected tab*/
  166. int cX = curX +  (tabWidth - tabGap) * curSelect;
  167. Rect cR = new Rect(cX, 0, cX + tabWidth, tabHeight);
  168. npCur.draw(canvas, cR);
  169. //draw current text
  170. paint.setColor(0xff456789);
  171. canvas.drawText(tabLists.get(curSelect).name, cX + tabGap, (tabHeight + TEXT_SIZE) >> 1, paint);
  172. /*draw add button*/
  173. canvas.drawBitmap(bitAdd, curX + (tabWidth - tabGap) * tabNum, 0, paint);
  174. }
  175. }
  176. @Override
  177. public boolean onTouch(View v, MotionEvent event) {
  178. if (mGestureDetector.onTouchEvent(event)) {
  179. return true;
  180. }
  181. if(event.getAction() == MotionEvent.ACTION_UP) {
  182. if(isDraging ) {
  183. if(dragSelectIndex != curSelect){
  184. if(dragSelectIndex >= tabNum){
  185. dragSelectIndex = tabNum - 1;
  186. }
  187. TabItem tempItem = tabLists.elementAt(curSelect);
  188. tabLists.removeElementAt(curSelect);
  189. tabLists.add(dragSelectIndex, tempItem);
  190. }
  191. float x = event.getX();
  192. curSelect = (int) ((x - curX) / (tabWidth - tabGap));
  193. if(curSelect >= tabNum){
  194. curSelect = tabNum - 1;
  195. }
  196. isDraging  = false;
  197. dragSelectIndex = -1;
  198. dragCurrentX = 0;
  199. dragSavedX = 0;
  200. invalidate();
  201. }
  202. }
  203. return false;
  204. }
  205. /**选项点击事件设置*/
  206. public void setOnTabItemClickListener(OnTabItemClickListener click) {
  207. this.clickListener = click;
  208. }
  209. /**选项点击事件接口*/
  210. public interface OnTabItemClickListener {
  211. public void onclickListenr(int index);
  212. }
  213. @Override
  214. public boolean onDown(MotionEvent event) {
  215. float x = event.getX();
  216. savedClickIndex = (int) ((x - curX) / (tabWidth - tabGap));
  217. if(savedClickIndex == curSelect){
  218. isDraging = true;
  219. dragSavedX = savedX;
  220. clickListener.onclickListenr(savedClickIndex);
  221. }
  222. return false;
  223. }
  224. @Override
  225. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
  226. float velocityY) {
  227. if(isDraging ) {
  228. if(dragSelectIndex != curSelect){
  229. if(dragSelectIndex >= tabNum){
  230. dragSelectIndex = tabNum - 1;
  231. }
  232. TabItem tempItem = tabLists.elementAt(curSelect);
  233. tabLists.removeElementAt(curSelect);
  234. tabLists.add(dragSelectIndex, tempItem);
  235. }
  236. float x = e2.getX();
  237. curSelect = (int) ((x - curX) / (tabWidth - tabGap));
  238. if(curSelect >= tabNum){
  239. curSelect = tabNum - 1;
  240. }
  241. isDraging  = false;
  242. dragSelectIndex = -1;
  243. dragCurrentX = 0;
  244. dragSavedX = 0;
  245. invalidate();
  246. }
  247. return true;
  248. }
  249. @Override
  250. public void onLongPress(MotionEvent event) {
  251. }
  252. @Override
  253. public boolean onScroll(MotionEvent e1, MotionEvent e2,
  254. float distanceX, float distanceY) {
  255. int tempWidth = (tabWidth - tabGap) * tabNum + tabAddWidth;
  256. if(isDraging){
  257. //drag
  258. int nextX = (int) (dragSavedX + e2.getX() - e1.getX());
  259. dragSelectIndex = (int) ((e2.getX() - curX) / (tabWidth - tabGap));
  260. dragCurrentX = nextX;
  261. invalidate();
  262. }else{
  263. //move
  264. int nextX = (int) (savedX - distanceX);
  265. if(tempWidth > screenWidth && (nextX <=0  && nextX + tempWidth >= screenWidth)){
  266. curX = nextX;
  267. savedX = curX;
  268. invalidate();
  269. }
  270. }
  271. return false;
  272. }
  273. @Override
  274. public void onShowPress(MotionEvent event) {
  275. }
  276. @Override
  277. public boolean onSingleTapUp(MotionEvent event) {
  278. float x = event.getX();
  279. int curClickIndex = (int) ((x - curX) / (tabWidth - tabGap));
  280. if(savedClickIndex == curClickIndex){
  281. if(curClickIndex < tabNum){
  282. setCurrentSelect(curClickIndex);
  283. clickListener.onclickListenr(curClickIndex);
  284. }else if(curClickIndex == tabNum){
  285. tabLists.add(new TabItem());
  286. tabNum++;
  287. curX = screenWidth - tabAddWidth - (tabWidth - tabGap) * tabNum;
  288. setCurrentSelect(tabNum - 1);
  289. clickListener.onclickListenr(curClickIndex);
  290. invalidate();
  291. }
  292. }
  293. savedClickIndex = -1;
  294. savedX = curX;
  295. return false;
  296. }
  297. }

tabItem类:

  1. public class TabItem{
  2. public int index;
  3. public String name = "New T

自定义tab bar控件 学习资料的更多相关文章

  1. 学习笔记:Tab Bar 控件使用详解

    注意这里是:Tab Bar 不是Tab Bar Controller. Tab bar是继承UIView,所以可以添加到ViewController里.是View就可以add到另一个View上去.Ta ...

  2. 通过编写串口助手工具学习MFC过程——(七)添加Tab Control控件

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  3. DevExpress控件学习总结(转)

    DevExpress控件学习总结   1.Navigation & Layout 1.1 Bar Manager 如果想在窗体或用户控件(user control)上添加工具条(bars)或弹 ...

  4. (转)sl简单自定义win窗体控件

    sl简单自定义win窗体控件      相信大家接触过不少win窗体控件ChildWin子窗口就的sl自带的一个  而且网上也有很多类似的控件,而今天我和大家分享下自己制作个win窗体控件,希望对初学 ...

  5. WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 下拉选 ...

  6. C# Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面

    个人理解,开发应用程序的目的,不论是B/S或是C/S结构类型,无非就是实现可供用户进行查.增.改.删,其中查询用到最多,开发设计的场景也最为复杂,包括但不限于:表格记录查询.报表查询.导出文件查询等等 ...

  7. iOS开发UI篇—Date Picker和UITool Bar控件简单介绍

    iOS开发UI篇—Date Picker和UITool Bar控件简单介绍 一.Date Picker控件 1.简单介绍: Date Picker显示时间的控件 有默认宽高,不用设置数据源和代理 如何 ...

  8. jquery和css自定义video播放控件

    下面介绍一下通过jquery和css自定义video播放控件. Html5 Video是现在html5最流行的功能之一,得到了大多数最新版本的浏览器支持.包括IE9,也是如此.不同的浏览器提供了不同的 ...

  9. Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面 z

    http://www.cnblogs.com/zuowj/p/4504130.html 不论是B/S或是C/S结构类型,无非就是实现可供用户进行查.增.改.删,其中查询用到最多,开发设计的场景 也最为 ...

随机推荐

  1. Java 线程池框架核心代码分析

    前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...

  2. 20145120 《Java程序设计》第2周学习总结

    20145120 <Java程序设计>第2周学习总结 教材学习内容总结 因为前面有学习过C语言以及汇编语言,类型.运算符.流程控制等很多都是之前接触过的,因此在学习第三章的时候感觉并非十分 ...

  3. linux 下 安装 rpm 格式 的 mysql

    在Linux操作系统下,安装MYSQL有两种方式: 一种tar安装方式, 另外一种是rpm安装方式. 这两种安装方式有什么区别呢?尽管我们在Linux下常用tar来压缩/解压缩文件,但MYSQL的ta ...

  4. oracle——DDL

    一.一些概念 定义: 主键--唯一标识一条记录,不能有重复的,不允许为空 外键--表的外键是另一表的主键, 外键可以有重复的, 可以是空值 索引--该字段没有重复值,但可以有一个空值 作用: 主键-- ...

  5. C#中Json和List/DataSet相互转换

    #region List<T> 转 Json        /// <summary>        /// List<T> 转 Json        /// & ...

  6. 在线最优化求解(Online Optimization)之四:RDA

    在线最优化求解(Online Optimization)之四:RDA 不论怎样,简单截断.TG.FOBOS都还是建立在SGD的基础之上的,属于梯度下降类型的方法,这类型方法的优点就是精度比较高,并且T ...

  7. [设计模式] 23 访问者模式 visitor Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问 ...

  8. PE文件结构详解(六)重定位

    前面两篇 PE文件结构详解(四)PE导入表 和 PE文件结构详解(五)延迟导入表 介绍了PE文件中比较常用的两种导入方式,不知道大家有没有注意到,在调用导入函数时系统生成的代码是像下面这样的: 在这里 ...

  9. 学习笔记--Grunt、安装、图文详解

    学习笔记--Git安装.图文详解 安装Git成功后,现在安装Gruntjs,官网:http://gruntjs.com/ 一.安装node 参考node.js 安装.图文详解 (最新的node会自动安 ...

  10. C# 构造函数的使用方法

    C#构造函数是一个特殊的类方法.在很多方面,包括访问修饰符.重载以及参数列表的语法等方面,构造函数与普通的方法是类似的.然而,在使用方面以及行为方面,构造函数也具有许多特殊的语法和语义规则. 下面列出 ...