android模仿移动MM Tab 点击 背景 滑动效果-阿里云开发者社区

开发者社区> 一叶飘舟> 正文

android模仿移动MM Tab 点击 背景 滑动效果

简介:
+关注继续查看

http://ouyangfeng521.iteye.com/blog/1112905


在玩MM时看到里面的tab 很酷 就学着做了一个

 

效果如下:

上代码 现在我把他搞成了一个控件了 用法跟ListView 差不多

控件类:

 

Java代码  收藏代码
  1. package com.test.scrolltab.control;  
  2.   
  3. import java.util.HashMap;  
  4.   
  5. import android.content.Context;  
  6. import android.content.res.TypedArray;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.drawable.Drawable;  
  9. import android.util.AttributeSet;  
  10. import android.util.Log;  
  11. import android.view.LayoutInflater;  
  12. import android.view.View;  
  13. import android.widget.LinearLayout;  
  14. import android.widget.TextView;  
  15.   
  16. import com.test.scrolltab.R;  
  17.   
  18. public class ScrcoolTab extends LinearLayout {  
  19.       
  20.     private int top,bottom; // 该布局的top与bottom  
  21.       
  22.     private LayoutInflater mInflater; // 控件xml 解析器  
  23.       
  24.     private OnItemClickListener clickListener; // 点击事件  
  25.       
  26.     private int defaultTab; // 默认选中第几个  
  27.       
  28.     private boolean move = false//标识是否可以移动,主要为了实现一个项点击后,用户不能点击第二个  
  29.       
  30.     private HashMap<Integer, Integer []> childPointCache = new HashMap<Integer, Integer[]>();  
  31.       
  32.     int childWidth  = 0//因为要控件居中,所以计算出每个控件可以有多少宽度  
  33.       
  34.     private int gleft,currentwidth,currentleft; // 上一个选中项的左坐标 当前点击的控件的宽度 当前点击的控件的左坐标  
  35.       
  36.     private Integer [] current = {0,0}; //tab 背景的坐标  
  37.       
  38.     private Drawable tabpictrue; //tab 移动的背景图片  
  39.       
  40.     private int tabpicpadding ; //tab 背景图片大于控件多少  
  41.       
  42.     private int moveunit; // tab图片第次移动多少  
  43.       
  44.     private int duration;//移动速度  
  45.       
  46.     public ScrcoolTab(Context context, AttributeSet attrs) {  
  47.         super(context, attrs);  
  48.         mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  49.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ScrcoolTab);  
  50.         final int N = a.getIndexCount();  
  51.         for (int i = 0; i < N; i++) {  
  52.             int attr = a.getIndex(i);  
  53.             switch (attr) {  
  54.                 case R.styleable.ScrcoolTab_tabpictrue:  
  55.                     tabpictrue = (Drawable) a.getDrawable(i);  
  56.                 break;  
  57.                 case R.styleable.ScrcoolTab_tabpicpadding:  
  58.                     tabpicpadding = a.getDimensionPixelSize(i, 5);  
  59.                 break;  
  60.                 case R.styleable.ScrcoolTab_moveunit:  
  61.                     moveunit = a.getDimensionPixelSize(i, 5);  
  62.                     break;  
  63.                 case R.styleable.ScrcoolTab_duration:  
  64.                     duration = a.getInt(i, 100);  
  65.                     break;  
  66.             }  
  67.         }  
  68.         Log.i("ScrcoolTab""construt");  
  69.     }  
  70.   
  71.     @Override  
  72.     protected void onDraw(Canvas canvas) {  
  73.         super.onDraw(canvas);  
  74.         if( ! isDrawItem()) return;   
  75.         tabpictrue.setBounds(current[0] -tabpicpadding ,top , current[0] + currentwidth + tabpicpadding , bottom);  
  76.         tabpictrue.draw(canvas);  
  77.     }  
  78.       
  79.       
  80.     @Override  
  81.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  82.         Log.i("ScrcoolTab""onLayout");  
  83.         super.onLayout(changed, l, t, r, b);  
  84.         top = t;  
  85.         bottom = b;  
  86.         int count = getChildCount();  
  87.         if(0 == count) return;  
  88.         int w = r- l;  
  89.         childWidth  = w / count;  
  90.          View v =null;  
  91.          Integer [] points = null;  
  92.         for(int i = 0;i < count;i++){  
  93.              v = getChildAt(i);  
  94.              points = scalcChildPoint(v, i);  
  95.              v.layout(points[0] ,((bottom - top) - v.getHeight()) /2  , points[1],  ((bottom - top) - v.getHeight()) /2 + v.getHeight());  
  96.              v.setTag(new Integer(i));  
  97.              v.setOnClickListener(new OnClickListener() {  
  98.                   
  99.                 @Override  
  100.                 public void onClick(View v) {  
  101.                     if( !move ){  
  102.                         move = true;  
  103.                         itemOnclick(v ,((Integer)v.getTag()).intValue() );  
  104.                     }  
  105.                 }  
  106.                   
  107.             });  
  108.         }  
  109.         //set default tab  
  110.         View mDefaultTab = getChildAt(defaultTab);  
  111.         if(null != mDefaultTab){  
  112.             itemOnclick(v , defaultTab);  
  113.         }  
  114.     }  
  115.       
  116.     public synchronized void update(View v ,int position){  
  117.         Log.i("ScrcoolTab""update");  
  118.         current = childPointCache.get(new Integer(position));  
  119.         currentleft = current [0];  
  120.         currentwidth = v.getWidth(); // 得到当前点击的控件的宽度  
  121.         //如果重复点一个项,则不会移动  
  122.         if(gleft == current [0]) {  
  123.             move = false//下一个点击可以移动  
  124.             return ;  
  125.         }  
  126.         clickListener.onItemClickListener(v, ((Integer)v.getTag()).intValue());//通知设置监听  
  127.         Log.i("ScrcoolTab""tab moved");  
  128.         defaultTab = position;  
  129.         final boolean  pathleft  = gleft > current[0] ? true : false;//判断是向左还是向右  
  130.         final int num = Math.abs((gleft - current[0]) / moveunit);  
  131.         int i = 0;  
  132.         while( i < num){  
  133.             if( pathleft ){  
  134.                 gleft = gleft - moveunit;  
  135.                 current [0] =  gleft;  
  136.             }else{  
  137.                 gleft = gleft + moveunit;  
  138.                 current [0] =  gleft;  
  139.             }  
  140.             try {  
  141.                 Thread.sleep(duration);  
  142.             } catch (InterruptedException e) {  
  143.                 e.printStackTrace();  
  144.             }  
  145.             Log.i("ScrcoolTab""Thread: left"+current[0]);  
  146.             postInvalidate();  
  147.             i++;  
  148.         }  
  149.         //校正 因为除数可能有精度损失  
  150.         if(gleft != currentleft){  
  151.             current [0] = currentleft;  
  152.             postInvalidate();  
  153.         }  
  154.         gleft = current[0];  
  155.         move = false;  
  156.     }  
  157.       
  158.     /** 
  159.      * 当点击一项时,移动背景坐标 
  160.      * @param v 
  161.      */  
  162.     public synchronized void itemOnclick(final View v ,final int position){  
  163.         Log.i("ScrcoolTab""itemOnclick position:" + position);  
  164.           
  165.         new Thread( new  Runnable() {  
  166.               
  167.             @Override  
  168.             public void run() {  
  169.                 update (v , position);  
  170.             }  
  171.               
  172.         }).start();  
  173.           
  174.     }  
  175.       
  176.     /** 
  177.      * 设置数据适配器 
  178.      * @param adapter 
  179.      */  
  180.     public void setAdapter(ScrcoolTabAdapter adapter){  
  181.         Log.i("ScrcoolTab""setAdapter");  
  182.         if(null != adapter && 0 != adapter.getResource() && null != adapter.getData()){  
  183.             View view = null;  
  184.             for(String str : adapter.getData()){  
  185.                 view = mInflater.inflate(adapter.getResource(),this ,false);  
  186.                 if(view instanceof TextView) ((TextView)view).setText(str);  
  187.                 this.addView(view);  
  188.             }  
  189.         }  
  190.     }  
  191.       
  192.     /** 
  193.      * 计算每个子控件的坐标 
  194.      * @param view 
  195.      * @param position 
  196.      * @return 
  197.      */  
  198.     public Integer [] scalcChildPoint(View view ,int position){  
  199.         Integer[] points = new Integer [2];  
  200.         points [0] =  childWidth * position  + (childWidth - view.getWidth())/2;  
  201.         points [1] =  points [0] + view.getWidth();  
  202.         Log.i("ScrcoolTab""scalcChildPoint position :" + position + "left:" + points [0] + "right:" + points [1]);  
  203.         childPointCache.put(new Integer(position), points);  
  204.         return points;  
  205.     }  
  206.       
  207.     /** 
  208.      * 是否画背景图片taab 
  209.      * @return 
  210.      */  
  211.     private boolean isDrawItem(){  
  212.         if(current [0] > 0 ) return true;  
  213.         else return false;  
  214.     }  
  215.       
  216.     /** 
  217.      * 设置默认选中 
  218.      * @param tab 
  219.      */  
  220.     public void setDefaultTab(int tab){  
  221.         Log.i("ScrcoolTab""setDefaultTab");  
  222.         this.defaultTab = tab;  
  223.     }  
  224.       
  225.     @Override  
  226.     protected void onAttachedToWindow() {  
  227.         super.onAttachedToWindow();  
  228.         Log.i("ScrcoolTab""onAttachedToWindow");  
  229.     }  
  230.       
  231.     /** 
  232.      * 得到当前选中的项 
  233.      * @return 
  234.      */  
  235.     public int getFocus() {  
  236.         return defaultTab;  
  237.     }  
  238.   
  239.     /** 
  240.      * 当点一项时 调用事件 
  241.      * @param clickListener 
  242.      */  
  243.     public void setOnItemClickListener(OnItemClickListener clickListener){  
  244.         this.clickListener = clickListener;  
  245.     }  
  246.       
  247.     /** 
  248.      * 事件接口 
  249.      * 
  250.      */  
  251.     public interface OnItemClickListener {  
  252.         void onItemClickListener(View v , int position);  
  253.     }  
  254. }  
 

 

控件适配器类:

Java代码  收藏代码
  1. package com.test.scrolltab.control;  
  2.   
  3. public class ScrcoolTabAdapter {  
  4.       
  5.     private int resource;  
  6.   
  7.     private String[] data;  
  8.   
  9.     public int getResource() {  
  10.         return resource;  
  11.     }  
  12.   
  13.     public void setResource(int resource) {  
  14.         this.resource = resource;  
  15.     }  
  16.   
  17.     public String[] getData() {  
  18.         return data;  
  19.     }  
  20.   
  21.     public void setData(String[] data) {  
  22.         this.data = data;  
  23.     }  
  24.   
  25.     public ScrcoolTabAdapter(int resource, String[] data) {  
  26.         super();  
  27.         this.resource = resource;  
  28.         this.data = data;  
  29.     }  
  30. }  

 用法:

xml 布局文件:

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:control="http://schemas.android.com/apk/res/com.test.scrolltab"  
  4.     android:orientation="vertical" android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent" >  
  6.     <com.test.scrolltab.control.ScrcoolTab  
  7.         android:id="@+id/scrcoolTab" android:layout_height="wrap_content"  
  8.         android:layout_width="fill_parent" android:gravity="center_vertical"  
  9.         control:tabpictrue="@drawable/bg_item_t" android:background="@drawable/bg_t"  
  10.         control:tabpicpadding="5dip"  control:moveunit="15dip" control:duration="50">  
  11.               
  12.     </com.test.scrolltab.control.ScrcoolTab>  
  13.   
  14. </LinearLayout>  

  一个tab的布局:

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <TextView android:layout_width="wrap_content"  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:layout_height="wrap_content" style="@style/text_style"  
  5.     android:onClick="itemOnclick" />  

 activity调用代码:

Java代码  收藏代码
  1. package com.test.scrolltab;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Process;  
  6. import android.view.View;  
  7. import android.view.ViewParent;  
  8.   
  9. import com.test.scrolltab.control.ScrcoolTab;  
  10. import com.test.scrolltab.control.ScrcoolTabAdapter;  
  11. import com.test.scrolltab.control.ScrcoolTab.OnItemClickListener;  
  12.   
  13. public class ScrollTabActivity extends Activity {  
  14.       
  15.     private ScrcoolTab scrcoolTab;  
  16.       
  17.     @Override  
  18.     public void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.main);  
  21.         scrcoolTab = (ScrcoolTab) findViewById(R.id.scrcoolTab);  
  22.         scrcoolTab.setAdapter(new ScrcoolTabAdapter(R.layout.tab_item,new String []{"进入首页","用户调研","下载中心","联系我们"}));  
  23.         scrcoolTab.setOnItemClickListener(new OnItemClickListener() {  
  24.               
  25.             @Override  
  26.             public void onItemClickListener(View v, int position) {  
  27. //              Toast.makeText(ScrollTabActivity.this, "点击了" + position, Toast.LENGTH_SHORT).show();  
  28.             }  
  29.         });  
  30. //        scrcoolTab.setDefaultTab(1);  
  31.     }  
  32.       
  33.     public void itemOnclick(View v){  
  34.       ViewParent parent =   v.getParent().getParent();  
  35.       if(parent instanceof ScrcoolTab){  
  36.           ScrcoolTab tab = (ScrcoolTab) parent;  
  37.           tab.postInvalidate();  
  38.       }  
  39.       System.out.println(parent);  
  40.     }  
  41.      
  42.    @Override  
  43.     public void finish() {  
  44.         super.finish();  
  45.         Process.killProcess(Process.myPid());  
  46.     }  
  47.       
  48. }  



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Axure制作Tab切换效果
axure 作为一款原型工具,能够帮助我们快速的设计原型,从而将产品人员的想法快速准确的传递给技术人员。 我们希望的最终效果如下图: Technorati 标签: axure,原型,tab,切换 最简单的一种办法就是通过 Dynamic Panels 来实现。
619 0
Android Studio 使用ViewPager + Fragment实现滑动菜单Tab效果 --简易版
描述:         之前有做过一个记账本APP,拿来练手的,做的很简单,是用Eclipse开发的;         最近想把这个APP重新完善一下,添加了一些新的功能,并选用Android Studio来开发;         APP已经完善了一部分,现在就想把已经做好的功能整理一下,记录下来。
2450 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
3951 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
5663 0
Android按钮点击效果的实现(selector)
步骤 1 放置两张图片ok1和ok2到drawable-mdpi文件夹中 2 在layout文件夹下建立xml文件,如下 3 main.
587 0
+关注
1635
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载