~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46704745

介绍

昨天晚上写了一个Android的滑动开关, 即SlideSwitch。

效果例如以下:

实现

实现的思路事实上非常easy。监听控件上的touch事件,并不断刷新,让滑块在手指的位置上绘出,达到滑块跟着手指滑动的显示效果。

先看一下代码:

SlideSwitch.java (7月3日有改动:在touch事件里调用onStateChangedListener前添加判空)

  1. package com.incell.view;
  2. import android.content.Context;
  3. import android.graphics.Canvas;
  4. import android.graphics.Color;
  5. import android.graphics.Paint;
  6. import android.util.AttributeSet;
  7. import android.view.MotionEvent;
  8. import android.view.View;
  9. public class SlideSwitch extends View{
  10. private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗锯齿
  11. boolean isOn = false;
  12. float curX = 0;
  13. float centerY; //y固定
  14. float viewWidth;
  15. float radius;
  16. float lineStart; //直线段開始的位置(横坐标,即
  17. float lineEnd; //直线段结束的位置(纵坐标
  18. float lineWidth;
  19. final int SCALE = 4; // 控件长度为滑动的圆的半径的倍数
  20. OnStateChangedListener onStateChangedListener;
  21. public SlideSwitch(Context context, AttributeSet attrs, int defStyle) {
  22. super(context, attrs, defStyle);
  23. }
  24. public SlideSwitch(Context context, AttributeSet attrs) {
  25. super(context, attrs);
  26. }
  27. public SlideSwitch(Context context) {
  28. super(context);
  29. }
  30. @Override
  31. public boolean onTouchEvent(MotionEvent event) {
  32. // TODO Auto-generated method stub
  33. curX = event.getX();
  34. if(event.getAction() == MotionEvent.ACTION_UP)
  35. {
  36. if(curX > viewWidth / 2)
  37. {
  38. curX = lineEnd;
  39. if(false == isOn)
  40. {
  41. //仅仅有状态发生改变才调用回调函数, 下同
  42. if(null != onStateChangedListener)
  43. {
  44. onStateChangedListener.onStateChanged(true);
  45. }
  46. isOn = true;
  47. }
  48. }
  49. else
  50. {
  51. curX = lineStart;
  52. if(true == isOn)
  53. {
  54. if(null != onStateChangedListener)
  55. {
  56. onStateChangedListener.onStateChanged(false);
  57. }
  58. isOn = false;
  59. }
  60. }
  61. }
  62. /*通过刷新调用onDraw*/
  63. this.postInvalidate();
  64. return true;
  65. }
  66. @Override
  67. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  68. // TODO Auto-generated method stub
  69. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  70. /*保持宽是高的SCALE / 2倍, 即圆的直径*/
  71. this.setMeasuredDimension(this.getMeasuredWidth(), this.getMeasuredWidth() * 2 / SCALE);
  72. viewWidth = this.getMeasuredWidth();
  73. radius = viewWidth / SCALE;
  74. lineWidth = radius * 2f; //直线宽度等于滑块直径
  75. curX = radius;
  76. centerY = this.getMeasuredWidth() / SCALE; //centerY为高度的一半
  77. lineStart = radius;
  78. lineEnd = (SCALE - 1) * radius;
  79. }
  80. @Override
  81. protected void onDraw(Canvas canvas) {
  82. // TODO Auto-generated method stub
  83. super.onDraw(canvas);
  84. /*限制滑动范围*/
  85. curX = curX > lineEnd?lineEnd:curX;
  86. curX = curX < lineStart?
  87. lineStart:curX;
  88. /*划线*/
  89. mPaint.setStyle(Paint.Style.STROKE);
  90. mPaint.setStrokeWidth(lineWidth);
  91. /*左边部分的线,绿色*/
  92. mPaint.setColor(Color.BLUE);
  93. canvas.drawLine(lineStart, centerY, curX, centerY, mPaint);
  94. /*右边部分的线,灰色*/
  95. mPaint.setColor(Color.GRAY);
  96. canvas.drawLine(curX, centerY, lineEnd, centerY, mPaint);
  97. /*画圆*/
  98. /*画最左和最右的圆,直径为直线段宽度。 即在直线段两边分别再加上一个半圆*/
  99. mPaint.setStyle(Paint.Style.FILL);
  100. mPaint.setColor(Color.GRAY);
  101. canvas.drawCircle(lineEnd, centerY, lineWidth / 2, mPaint);
  102. mPaint.setColor(Color.BLUE);
  103. canvas.drawCircle(lineStart, centerY, lineWidth / 2, mPaint);
  104. /*圆形滑块*/
  105. mPaint.setColor(Color.LTGRAY);
  106. canvas.drawCircle(curX, centerY, radius , mPaint);
  107. }
  108. /*设置开关状态改变监听器*/
  109. public void setOnStateChangedListener(OnStateChangedListener o)
  110. {
  111. this.onStateChangedListener = o;
  112. }
  113. /*内部接口。开关状态改变监听器*/
  114. public interface OnStateChangedListener
  115. {
  116. public void onStateChanged(boolean state);
  117. }
  118. }

凝视应该非常具体了。主要有下面几点。

1、重写了onMeasure方法,使控件高度依赖于控件的宽度

这样不论在布局文件里怎样设置。总能保证控件的宽高比

2、控制好滑块的活动范围

3、定义内部接口OnStateChangedListener,并在自己定义控件里定义了其对象以及从外部赋值的方法setOnStateChangedListener,以便对开关状态更改事件进行监听并调用回调

使用及Demo

在布局文件里加入该控件就可以使用。Demo效果为动图展示效果(demo里颜色为绿色,动图为蓝色是由于绿色会导致截取gif时出问题,暂时更改的)。

Demo中布局文件例如以下:

activity_main.xml:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5. <com.example.slideswitchexample.SlideSwitch
  6. android:id="@+id/slide_switch"
  7. android:layout_width="200dp"
  8. android:layout_height="wrap_content"
  9. android:layout_centerInParent="true"/>
  10. </RelativeLayout>

Demo中Activity代码例如以下:

MainActivity.java

  1. package com.example.slideswitchexample;
  2. import com.example.slideswitchexample.SlideSwitch.OnStateChangedListener;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.widget.Toast;
  6. public class MainActivity extends Activity {
  7. SlideSwitch sSwitch;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. sSwitch = (SlideSwitch) this.findViewById(R.id.slide_switch);
  13. sSwitch.setOnStateChangedListener(new OnStateChangedListener(){
  14. @Override
  15. public void onStateChanged(boolean state) {
  16. // TODO Auto-generated method stub
  17. if(true == state)
  18. {
  19. Toast.makeText(MainActivity.this, "开关已打开", 1000).show();
  20. }
  21. else
  22. {
  23. Toast.makeText(MainActivity.this, "开关已关闭", 1000).show();
  24. }
  25. }
  26. });
  27. }
  28. }

点此下载Demoproject

【Android】自己定义控件实现可滑动的开关(switch)的更多相关文章

  1. Android自己定义控件系列五:自己定义绚丽水波纹效果

    尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自己定义控件实现一个比較有趣的效果 ...

  2. Android自己定义控件:进度条的四种实现方式

    前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源代码下载)http://down ...

  3. android 自己定义控件

    Android自己定义View实现非常easy 继承View,重写构造函数.onDraw.(onMeasure)等函数. 假设自己定义的View须要有自己定义的属性.须要在values下建立attrs ...

  4. Android自己定义控件皮肤

    Android自己定义控件皮肤 对于Android的自带控件,其外观仅仅能说中规中矩,而我们平时所示Android应用中,一个简单的button都做得十分美观.甚至于很多button在按下时的外观都有 ...

  5. android 自己定义控件属性(TypedArray以及attrs解释)

    近期在捣鼓android 自己定义控件属性,学到了TypedArray以及attrs.在这当中看了一篇大神博客Android 深入理解Android中的自己定义属性.我就更加深入学习力一番.我就沿着这 ...

  6. Android自己定义控件系列二:自己定义开关button(一)

    这一次我们将会实现一个完整纯粹的自己定义控件,而不是像之前的组合控件一样.拿系统的控件来实现.计划分为三部分:自己定义控件的基本部分,自己定义控件的触摸事件的处理和自己定义控件的自己定义属性: 以下就 ...

  7. Android自己定义控件之轮播图控件

    背景 近期要做一个轮播图的效果.网上看了几篇文章.基本上都能找到实现,效果还挺不错,可是在写的时候感觉每次都要单独去又一次在Activity里写一堆代码.于是自己封装了一下.这里仅仅是做了下封装成一个 ...

  8. Android自己定义控件系列三:自己定义开关button(二)

    接上一篇自己定义开关button(一)的内容继续.上一次实现了一个开关button的基本功能.即自己定义了一个控件.开关button,实现了点击切换开关状态的功能.今天我们想在此基础之上.进一步实现触 ...

  9. Android自己定义控件2-简单的写字板控件

    概述 上一篇文章我们对自己定义控件进行了一个大体的知识介绍. 今天就来学习自己定义一个简单的写字板控件. 先来看看效果图 就是简单的依据手指写下的轨迹去画出内容 实现 在上一篇文章里提到了androi ...

随机推荐

  1. 【漏洞预警】Apache ActiveMQ Fileserver远程代码执行漏洞(CVE-2016-3088)

    漏洞编码:CVE-2016-3088 实验环境:Linux Apache ActiveMQ版本号:Apache ActiveMQ 5.7.0 ----------------------------- ...

  2. C/C++ 之输入输出

    因为C++向下兼容C,所以有多种输入输出的方式,cin/cout十分简洁,但个人觉得不如scanf/printf来的强大,而且在做算法题时,后者运行速度也快些. scanf/printf #inclu ...

  3. vijos 1894 二分

    题意:在 Ninian 的花园里,有许多琼花,环绕着中间的凉亭.有 N 片琼花,组成一个环.Ninian 想在凉亭中发动 [セチの祈り] , 需要划分出三个区域的琼花,为了平均,要最大化面积最小的区域 ...

  4. Django1.7如何配置静态资源访问

    Django是非常轻量级的Web框架,今天散仙来看下如何在Django中配置静态的资源访问路径,一个中等规模的网站,可能就会有很多静态的资源需要访问,无论是html,txt,还是压缩包,有时候访问这些 ...

  5. HDU 4730 We Love MOE Girls (2013成都网络赛,签到水题)

    We Love MOE Girls Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. 【spark系列3】spark开发简单指南

    分布式数据集创建之textFile         文本文件的RDDs能够通过SparkContext的textFile方法创建,该方法接受文件的URI地址(或者机器上的文件本地路径,或者一个hdfs ...

  7. Microsoft Composition (MEF 2)

    This packages provides a version of the Managed Extensibility Framework (MEF) that is lightweight an ...

  8. c中的static变量

    当一个进程的全局变量被声明为static之后.它的中文名叫静态全局变量.静态全局变量和其它的全局变量的存储地点并没有差别.可是它仅仅在定义它的源文件内有效,其它源文件无法訪问它. static局部变量 ...

  9. UITableView的headerView展开缩放动画

    UITableView的headerView展开缩放动画 效果 源码 https://github.com/YouXianMing/Animations // // HeaderViewTapAnim ...

  10. 更改Mantis的logo

    1 准备好自己的logo,例如准备的logo为zhaoxiyu.gif.zxy.gif 2 把上面的两个logo存放到C:/mantis-1.0.0a3/images 3 打开C:/mantis-1. ...