//SlideSwitch.java

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

// layout xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:background="#fdfdfd"
  6. android:orientation="vertical"
  7. android:paddingLeft="10dip"
  8. android:paddingRight="10dip" >
  9. <ImageView
  10. android:id="@+id/imageView1"
  11. android:layout_width="fill_parent"
  12. android:layout_height="wrap_content"
  13. android:src="@drawable/top" />
  14. <RelativeLayout
  15. android:layout_width="fill_parent"
  16. android:layout_height="wrap_content" >
  17. <TextView
  18. android:id="@+id/textView1"
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. android:layout_alignParentLeft="true"
  22. android:layout_centerVertical="true"
  23. android:text="网络构图"
  24. android:textSize="15sp" />
  25. <com.example.hellojni.SlideSwitch
  26. android:id="@+id/slideSwitch1"
  27. android:layout_width="116dip"
  28. android:layout_height="46dip"
  29. android:layout_alignParentRight="true"
  30. android:layout_centerVertical="true" />
  31. </RelativeLayout>
  32. <RelativeLayout
  33. android:layout_width="fill_parent"
  34. android:layout_height="wrap_content" >
  35. <TextView
  36. android:id="@+id/textView2"
  37. android:layout_width="wrap_content"
  38. android:layout_height="wrap_content"
  39. android:layout_alignParentLeft="true"
  40. android:layout_centerVertical="true"
  41. android:text="保留原图"
  42. android:textSize="15sp" />
  43. <com.example.hellojni.SlideSwitch
  44. android:id="@+id/slideSwitch2"
  45. android:layout_width="116dip"
  46. android:layout_height="46dip"
  47. android:layout_alignParentRight="true"
  48. android:layout_centerVertical="true" />
  49. </RelativeLayout>
  50. <RelativeLayout
  51. android:layout_width="fill_parent"
  52. android:layout_height="wrap_content" >
  53. <TextView
  54. android:id="@+id/textView3"
  55. android:layout_width="wrap_content"
  56. android:layout_height="wrap_content"
  57. android:layout_alignParentLeft="true"
  58. android:layout_centerVertical="true"
  59. android:text="拍照声音"
  60. android:textSize="15sp" />
  61. <com.example.hellojni.SlideSwitch
  62. android:id="@+id/slideSwitch3"
  63. android:layout_width="116px"
  64. android:layout_height="46px"
  65. android:layout_alignParentRight="true"
  66. android:layout_centerVertical="true" />
  67. </RelativeLayout>
  68. <TextView
  69. android:id="@+id/textViewTip"
  70. android:layout_width="fill_parent"
  71. android:layout_height="wrap_content"
  72. android:gravity="center"
  73. android:text="TextView" />
  74. </LinearLayout>

SlideSwitch的更多相关文章

  1. Android开源项目分类汇总

    目前包括: Android开源项目第一篇——个性化控件(View)篇   包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView. ...

  2. GitHub开源项目总结

    SwipeRefreshLayout 地址:https://github.com/hanks-zyh/SwipeRefreshLayout 首页轮播的Tab样式,PagerSlidingTab 地址: ...

  3. Android 开源项目分类汇总(转)

    Android 开源项目分类汇总(转) ## 第一部分 个性化控件(View)主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Galler ...

  4. Android 开源项目分类汇总

    Android 开源项目分类汇总 Android 开源项目第一篇——个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView ...

  5. JQuery淡入淡出 banner切换特效

    附件中提供另一种实现方式 基本类似 主要的实现方法如下: var ShowAD=function(i){   showImg.eq(i).animate({opacity:1},settings.sp ...

  6. Android开源经典项目

    目前包括: Android开源项目第一篇--个性化控件(View)篇   包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView. ...

  7. 【Android】自己定义控件实现可滑动的开关(switch)

    ~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46704745 介绍 昨天晚上写了一个Android的滑动开关, 即SlideSwi ...

  8. Android常用酷炫控件(开源项目)github地址汇总

    转载一个很牛逼的控件收集帖... 第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.Gri ...

  9. 做出一个SwitchButton的效果,并详细学习一下onDraw(Canvas canvas)方法的使用

    代码的灵感和原理主要来自于android自定义开关控件-SlideSwitch http://blog.csdn.net/singwhatiwanna/article/details/9254309这 ...

随机推荐

  1. 从客户端中检测到有潜在危险的Request.Form 值

    今天往MVC中加入了一个富文本编辑框,在提交信息的时候报了如下的错误:从客户端(Content="<EM ><STRONG ><U >这是测试这...&q ...

  2. ios kaifa

    弹窗提示 { ////ios 7 弹窗 // UIAlertView *alert1=[[UIAlertView alloc] // initWithTitle:@"tishi" ...

  3. php5.3之前版本升级至5.3以及更高版本后部分语法简单归纳

    1. Deprecated: Assigning the return value of new by reference is deprecated in /usr/local/www/uugui/ ...

  4. drawRect导致内存暴增的真正原因

    那么现在我们分析一下drawRect导致内存暴增的真正原因: 重写drawRect为何会导致内存大量上涨? 要想搞明白这个问题,我们需要撸一撸在 iOS 程序上图形显示的原理.在 iOS 系统中所有显 ...

  5. mysqldump命令

    mysqldump命令 mysqldump命令是mysql数据库中备份工具,用于将MySQL服务器中的数据库以标准的sql语言的方式导出,并保存到文件中. 语法 mysqldump(选项) 选项 -- ...

  6. Python3基础 print 自带换行功能

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  7. <转>如何改变讨好型人格 | 你根本不需要讨好任何人

    在我过去二十多年的生命里一直是一个“讨好者”. 我总是活在别人对我的期待中,我总是不停的追逐着别人对我的认可,我总是像个卑微的奴才一样去满足别人的需求. 但就和大多数的“讨好者”一样,我们越是寻求别人 ...

  8. Cheatsheet: 2013 09.01 ~ 09.09

    .NET Multi Threaded WebScraping in CSharpDotNetTech .NET Asynchronous Patterns An Overview of Projec ...

  9. Bug2算法的实现(RobotBASIC环境中仿真)

    移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求--避障.之前简单介绍过Bug避障算法,但仅仅了解大致理论而不亲自动手实现一遍很难有深刻的印象,只能说似懂非懂.我不是天才,不 ...

  10. Systematic LncRNA Classification

    Systematic LncRNA Classification From: http://www.arraystar.com/Services/Services_main.asp?ID=307 An ...