您当前的位置: 首页 >  ide

xiangzhihong8

暂无认证

  • 2浏览

    0关注

    1324博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

滑动开关按钮SlideSwich

xiangzhihong8 发布时间:2014-02-27 11:29:24 ,浏览量:2

iphone上有开关控件,很漂亮,其实android4.0以后也有switch控件,但是只能用在4.0以后的系统中,这就失去了其使用价值,而且我觉得它的界面也不是很好看。最近看到了百度魔拍上面的一个控件,觉得很漂亮啊,然后反编译了下,尽管没有混淆过,但是还是不好读,然后就按照自己的想法写了个,功能和百度魔拍类似。

下面是百度魔拍的效果和SlideSwitch的效果

apk下载地址:http://home.ustc.edu.cn/~voa/res/HelloJni.apk

2.原理
继承自view类,override其onDraw函数,把两个背景图(一个灰的一个红的)和一个开关图(圆开关)通过canvas画出来;同时override其onTouchEvent函数,实现滑动效果;最后开启一个线程做动画,实现缓慢滑动的效果。
3. 代码 //SlideSwitch.java
[java]  view plain copy
  1. package com.example.hellojni;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.Resources;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Color;  
  9. import android.graphics.Paint;  
  10. import android.graphics.Rect;  
  11. import android.graphics.Typeface;  
  12. import android.util.AttributeSet;  
  13. import android.util.Log;  
  14. import android.view.MotionEvent;  
  15. import android.view.View;  
  16. import android.view.ViewGroup.LayoutParams;  
  17.   
  18. /** 
  19.  * SlideSwitch 仿iphone滑动开关组件,仿百度魔图滑动开关组件 
  20.  * 组件分为三种状态:打开、关闭、正在滑动 
  21.  * 使用方法:         
  22.  * 
    SlideSwitch slideSwitch = new SlideSwitch(this); 
  23.  *slideSwitch.setOnSwitchChangedListener(onSwitchChangedListener); 
  24.  *linearLayout.addView(slideSwitch); 
  25.  
  26. 注:也可以加载在xml里面使用 
  27.  * @author scott 
  28.  * 
  29.  */  
  30. public class SlideSwitch extends View  
  31. {  
  32.     public static final String TAG = "SlideSwitch";  
  33.     public static final int SWITCH_OFF = 0;//关闭状态  
  34.     public static final int SWITCH_ON = 1;//打开状态  
  35.     public static final int SWITCH_SCROLING = 2;//滚动状态  
  36.       
  37.     //用于显示的文本  
  38.     private String mOnText = "打开";  
  39.     private String mOffText = "关闭";  
  40.   
  41.     private int mSwitchStatus = SWITCH_OFF;  
  42.   
  43.     private boolean mHasScrolled = false;//表示是否发生过滚动  
  44.   
  45.     private int mSrcX = 0, mDstX = 0;  
  46.       
  47.     private int mBmpWidth = 0;  
  48.     private int mBmpHeight = 0;  
  49.     private int mThumbWidth = 0;  
  50.   
  51.     private     Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  52.       
  53.     private OnSwitchChangedListener mOnSwitchChangedListener = null;  
  54.   
  55.     //开关状态图  
  56.     Bitmap mSwitch_off, mSwitch_on, mSwitch_thumb;  
  57.   
  58.     public SlideSwitch(Context context)   
  59.     {  
  60.         this(context, null);  
  61.     }  
  62.   
  63.     public SlideSwitch(Context context, AttributeSet attrs)   
  64.     {  
  65.         super(context, attrs);  
  66.         init();  
  67.     }  
  68.   
  69.     public SlideSwitch(Context context, AttributeSet attrs, int defStyle)  
  70.     {  
  71.         super(context, attrs, defStyle);  
  72.         init();  
  73.     }  
  74.   
  75.     //初始化三幅图片  
  76.     private void init()  
  77.     {  
  78.         Resources res = getResources();  
  79.         mSwitch_off = BitmapFactory.decodeResource(res, R.drawable.bg_switch_off);  
  80.         mSwitch_on = BitmapFactory.decodeResource(res, R.drawable.bg_switch_on);  
  81.         mSwitch_thumb = BitmapFactory.decodeResource(res, R.drawable.switch_thumb);  
  82.         mBmpWidth = mSwitch_on.getWidth();  
  83.         mBmpHeight = mSwitch_on.getHeight();  
  84.         mThumbWidth = mSwitch_thumb.getWidth();  
  85.     }  
  86.   
  87.     @Override  
  88.     public void setLayoutParams(LayoutParams params)   
  89.     {  
  90.         params.width = mBmpWidth;  
  91.         params.height = mBmpHeight;  
  92.         super.setLayoutParams(params);  
  93.     }  
  94.       
  95.     /** 
  96.      * 为开关控件设置状态改变监听函数 
  97.      * @param onSwitchChangedListener 参见 {@link OnSwitchChangedListener} 
  98.      */  
  99.     public void setOnSwitchChangedListener(OnSwitchChangedListener onSwitchChangedListener)  
  100.     {  
  101.         mOnSwitchChangedListener = onSwitchChangedListener;  
  102.     }  
  103.       
  104.     /** 
  105.      * 设置开关上面的文本 
  106.      * @param onText  控件打开时要显示的文本 
  107.      * @param offText  控件关闭时要显示的文本 
  108.      */  
  109.     public void setText(final String onText, final String offText)  
  110.     {  
  111.         mOnText = onText;  
  112.         mOffText =offText;  
  113.         invalidate();  
  114.     }  
  115.       
  116.     /** 
  117.      * 设置开关的状态 
  118.      * @param on 是否打开开关 打开为true 关闭为false 
  119.      */  
  120.     public void setStatus(boolean on)  
  121.     {  
  122.         mSwitchStatus = ( on ? SWITCH_ON : SWITCH_OFF);  
  123.     }  
  124.       
  125.     @Override  
  126.     public boolean onTouchEvent(MotionEvent event)  
  127.     {  
  128.         int action = event.getAction();  
  129.         Log.d(TAG, "onTouchEvent  x="  + event.getX());  
  130.         switch (action) {  
  131.         case MotionEvent.ACTION_DOWN:  
  132.             mSrcX = (int) event.getX();  
  133.             break;  
  134.         case MotionEvent.ACTION_MOVE:  
  135.             mDstX = Math.max( (int) event.getX(), 10);  
  136.             mDstX = Math.min( mDstX, 62);  
  137.             if(mSrcX == mDstX)  
  138.                 return true;  
  139.             mHasScrolled = true;  
  140.             AnimationTransRunnable aTransRunnable = new AnimationTransRunnable(mSrcX, mDstX, 0);  
  141.             new Thread(aTransRunnable).start();  
  142.             mSrcX = mDstX;  
  143.             break;  
  144.         case MotionEvent.ACTION_UP:  
  145.             if(mHasScrolled == false)//如果没有发生过滑动,就意味着这是一次单击过程  
  146.             {  
  147.                 mSwitchStatus = Math.abs(mSwitchStatus-1);  
  148.                 int xFrom = 10, xTo = 62;  
  149.                 if(mSwitchStatus == SWITCH_OFF)  
  150.                 {  
  151.                     xFrom = 62;  
  152.                     xTo = 10;  
  153.                 }  
  154.                 AnimationTransRunnable runnable = new AnimationTransRunnable(xFrom, xTo, 1);  
  155.                 new Thread(runnable).start();  
  156.             }  
  157.             else  
  158.             {  
  159.                 invalidate();  
  160.                 mHasScrolled = false;  
  161.             }  
  162.             //状态改变的时候 回调事件函数  
  163.             if(mOnSwitchChangedListener != null)  
  164.             {  
  165.                 mOnSwitchChangedListener.onSwitchChanged(this, mSwitchStatus);  
  166.             }  
  167.             break;  
  168.   
  169.         default:  
  170.             break;  
  171.         }  
  172.         return true;  
  173.     }  
  174.   
  175.     @Override  
  176.     protected void onSizeChanged(int w, int h, int oldw, int oldh)  
  177.     {  
  178.         super.onSizeChanged(w, h, oldw, oldh);  
  179.     }  
  180.   
  181.     @Override  
  182.     protected void onDraw(Canvas canvas)  
  183.     {  
  184.         super.onDraw(canvas);  
  185.         //绘图的时候 内部用到了一些数值的硬编码,其实不太好,  
  186.         //主要是考虑到图片的原因,图片周围有透明边界,所以要有一定的偏移  
  187.         //硬编码的数值只要看懂了代码,其实可以理解其含义,可以做相应改进。  
  188.         mPaint.setTextSize(14);  
  189.         mPaint.setTypeface(Typeface.DEFAULT_BOLD);  
  190.           
  191.         if(mSwitchStatus == SWITCH_OFF)  
  192.         {  
  193.             drawBitmap(canvas, null, null, mSwitch_off);  
  194.             drawBitmap(canvas, null, null, mSwitch_thumb);  
  195.             mPaint.setColor(Color.rgb(105, 105, 105));  
  196.             canvas.translate(mSwitch_thumb.getWidth(), 0);  
  197.             canvas.drawText(mOffText, 0, 20, mPaint);  
  198.         }  
  199.         else if(mSwitchStatus == SWITCH_ON)  
  200.         {  
  201.             drawBitmap(canvas, null, null, mSwitch_on);  
  202.             int count = canvas.save();  
  203.             canvas.translate(mSwitch_on.getWidth() - mSwitch_thumb.getWidth(), 0);  
  204.             drawBitmap(canvas, null, null, mSwitch_thumb);  
  205.             mPaint.setColor(Color.WHITE);  
  206.             canvas.restoreToCount(count);  
  207.             canvas.drawText(mOnText, 17, 20, mPaint);  
  208.         }  
  209.         else //SWITCH_SCROLING  
  210.         {  
  211.             mSwitchStatus = mDstX > 35 ? SWITCH_ON : SWITCH_OFF;  
  212.             drawBitmap(canvas, new Rect(0, 0, mDstX, mBmpHeight), new Rect(0, 0, (int)mDstX, mBmpHeight), mSwitch_on);  
  213.             mPaint.setColor(Color.WHITE);  
  214.             canvas.drawText(mOnText, 17, 20, mPaint);  
  215.   
  216.             int count = canvas.save();  
  217.             canvas.translate(mDstX, 0);  
  218.             drawBitmap(canvas, new Rect(mDstX, 0, mBmpWidth, mBmpHeight),  
  219.                           new Rect(0, 0, mBmpWidth - mDstX, mBmpHeight), mSwitch_off);  
  220.             canvas.restoreToCount(count);  
  221.   
  222.             count = canvas.save();  
  223.             canvas.clipRect(mDstX, 0, mBmpWidth, mBmpHeight);  
  224.             canvas.translate(mThumbWidth, 0);  
  225.             mPaint.setColor(Color.rgb(105, 105, 105));  
  226.             canvas.drawText(mOffText, 0, 20, mPaint);  
  227.             canvas.restoreToCount(count);  
  228.   
  229.             count = canvas.save();  
  230.             canvas.translate(mDstX - mThumbWidth / 2, 0);  
  231.             drawBitmap(canvas, null, null, mSwitch_thumb);  
  232.             canvas.restoreToCount(count);  
  233.         }  
  234.   
  235.     }  
  236.   
  237.     public void drawBitmap(Canvas canvas, Rect src, Rect dst, Bitmap bitmap)  
  238.     {  
  239.         dst = (dst == null ? new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()) : dst);  
  240.         Paint paint = new Paint();  
  241.         canvas.drawBitmap(bitmap, src, dst, paint);  
  242.     }  
  243.   
  244.     /** 
  245.      * AnimationTransRunnable 做滑动动画所使用的线程 
  246.      */  
  247.     private class AnimationTransRunnable implements Runnable  
  248.     {  
  249.         private int srcX, dstX;  
  250.         private int duration;  
  251.   
  252.         /** 
  253.          * 滑动动画 
  254.          * @param srcX 滑动起始点 
  255.          * @param dstX 滑动终止点 
  256.          * @param duration 是否采用动画,1采用,0不采用 
  257.          */  
  258.         public AnimationTransRunnable(float srcX, float dstX, final int duration)  
  259.         {  
  260.             this.srcX = (int)srcX;  
  261.             this.dstX = (int)dstX;  
  262.             this.duration = duration;  
  263.         }  
  264.   
  265.         @Override  
  266.         public void run()   
  267.         {  
  268.             final int patch = (dstX > srcX ? 5 : -5);  
  269.             if(duration == 0)  
  270.             {  
  271.                 SlideSwitch.this.mSwitchStatus = SWITCH_SCROLING;  
  272.                 SlideSwitch.this.postInvalidate();  
  273.             }  
  274.             else  
  275.             {  
  276.                 Log.d(TAG, "start Animation: [ " + srcX + " , " + dstX + " ]");  
  277.                 int x = srcX + patch;  
  278.                 while (Math.abs(x-dstX) > 5)   
  279.                 {  
  280.                     mDstX = x;  
  281.                     SlideSwitch.this.mSwitchStatus = SWITCH_SCROLING;  
  282.                     SlideSwitch.this.postInvalidate();  
  283.                     x += patch;  
  284.                     try   
  285.                     {  
  286.                         Thread.sleep(10);  
  287.                     }   
  288.                     catch (InterruptedException e)  
  289.                     {  
  290.                         e.printStackTrace();  
  291.                     }  
  292.                 }  
  293.                 mDstX = dstX;  
  294.                 SlideSwitch.this.mSwitchStatus = mDstX > 35 ? SWITCH_ON : SWITCH_OFF;  
  295.                 SlideSwitch.this.postInvalidate();  
  296.             }  
  297.         }  
  298.   
  299.     }  
  300.   
  301.     public static interface OnSwitchChangedListener  
  302.     {  
  303.         /** 
  304.          * 状态改变 回调函数 
  305.          * @param status  SWITCH_ON表示打开 SWITCH_OFF表示关闭 
  306.          */  
  307.         public abstract void onSwitchChanged(SlideSwitch obj, int status);  
  308.     }  
  309.   
  310. }  
// layout xml
[html]  view plain copy
  1.   
  2.   
  3.   
  4.       
  5.   
  6.       
  7.   
  8.           
  9.   
  10.           
  11.       
  12.   
  13.       
  14.   
  15.           
  16.   
  17.           
  18.       
  19.   
  20.       
  21.   
  22.           
  23.   
  24.           
  25.       
  26.   
  27.       
  28.   
关注
打赏
1482932726
查看更多评论
立即登录/注册

微信扫码登录

0.0486s