2013-12-28 17:25:01

网上看到一篇关于可滑动的ToogleButton的文章,有代码,觉得挺好,但是不符合我的要求,因此在他的代码基础上改了一些。(作者看到了勿喷啊,实在找不到原文了,只好把代码下载地址贴出来。)

源码下载地址: http://download.csdn.net/detail/zshq280017423/4240703

先来两张效果图:

然后上代码:

最主要的类是SlipButton.java

 package com.util;

 import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener; import com.view.SlipButton.R; public class SlipButton extends View implements OnTouchListener { private float DownX, NowX;// 按下时的x,当前的x
private float btn_on_left = ;
private float btn_off_left = ; private boolean NowChoose = false;// 记录当前按钮是否打开,true为打开,flase为关闭
private boolean isChecked;
private boolean OnSlip = false;// 记录用户是否在滑动的变量
private boolean isChgLsnOn = false; private OnChangedListener ChgLsn;
private Bitmap bg_on;
private Bitmap bg_off;
private Bitmap slip_btn; public SlipButton(Context context) {
super(context);
init();
} public SlipButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} private void init() { // 初始化
bg_on = BitmapFactory.decodeResource(getResources(),
R.drawable.split_left_1);
bg_off = BitmapFactory.decodeResource(getResources(),
R.drawable.split_right_1);
slip_btn = BitmapFactory.decodeResource(getResources(),
R.drawable.split_1); btn_off_left = bg_off.getWidth() - slip_btn.getWidth(); setOnTouchListener(this); // 设置监听器,也可以直接复写OnTouchEvent
} @Override
protected void onDraw(Canvas canvas) {// 绘图函数
super.onDraw(canvas); Matrix matrix = new Matrix();
Paint paint = new Paint();
float x; if (NowX < (bg_on.getWidth() / )) { // 滑动到前半段与后半段的背景不同,在此做判断
x = NowX - slip_btn.getWidth() / ;
canvas.drawBitmap(bg_off, matrix, paint);// 画出关闭时的背景
} else {
x = bg_on.getWidth() - slip_btn.getWidth() / ;
canvas.drawBitmap(bg_on, matrix, paint);// 画出打开时的背景
} if (OnSlip) {// 是否是在滑动状态,
if (NowX >= bg_on.getWidth()) {// 是否划出指定范围,不能让游标跑到外头,必须做这个判断
x = bg_on.getWidth() - slip_btn.getWidth() / ;// 减去游标1/2的长度...
} else if (NowX < ) {
x = ;
} else {
x = NowX - slip_btn.getWidth() / ;
}
} else {// 非滑动状态
if (NowChoose) {// 根据现在的开关状态设置画游标的位置
x = btn_off_left;
canvas.drawBitmap(bg_on, matrix, paint);// 初始状态为true时应该画出打开状态图片
} else {
x = btn_on_left;
}
}
if (isChecked) {
canvas.drawBitmap(bg_on, matrix, paint);
x = btn_off_left;
isChecked = !isChecked;
} if (x < ) {// 对游标位置进行异常判断...
x = ;
} else if (x > bg_on.getWidth() - slip_btn.getWidth()) {
x = bg_on.getWidth() - slip_btn.getWidth();
}
canvas.drawBitmap(slip_btn, x, , paint);// 画出游标. } public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {// 根据动作来执行代码
case MotionEvent.ACTION_DOWN:// 按下
if (event.getX() > bg_on.getWidth()
|| event.getY() > bg_on.getHeight()) {
return false;
}
OnSlip = true;
DownX = event.getX();
NowX = DownX;
break; case MotionEvent.ACTION_MOVE:// 滑动
Log.d("David", "event.getX = " + event.getX());
Log.d("David", "event.getY = " + event.getY());
NowX = event.getX();
boolean LastChoose = NowChoose; if (NowX >= (bg_on.getWidth() / )) {
NowChoose = true;
} else {
NowChoose = false;
} if (isChgLsnOn && (LastChoose != NowChoose)) { // 如果设置了监听器,就调用其方法..
ChgLsn.OnChanged(NowChoose);
}
break; case MotionEvent.ACTION_UP:// 松开
OnSlip = false;
break;
default:
}
invalidate();// 重画控件
return true;
} public void SetOnChangedListener(OnChangedListener l) {// 设置监听器,当状态修改的时候
isChgLsnOn = true;
ChgLsn = l;
} public interface OnChangedListener {
abstract void OnChanged(boolean CheckState);
} public void setCheck(boolean isChecked) {
this.isChecked = isChecked;
NowChoose = isChecked;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measuredHeight = measureHeight(heightMeasureSpec);
int measuredWidth = measureWidth(widthMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
} private int measureHeight(int measureSpec) { /*int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); // Default size if no limits are specified. int result = 500;
if (specMode == MeasureSpec.AT_MOST){
// Calculate the ideal size of your
// control within this maximum size.
// If your control fills the available
// space return the outer bound. result = specSize;
} else if (specMode == MeasureSpec.EXACTLY){
// If your control can fit within these bounds return that value.
result = specSize;
}*/
return bg_on.getHeight();
} private int measureWidth(int measureSpec) { /*int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); // Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST){
// Calculate the ideal size of your control
// within this maximum size.
// If your control fills the available space
// return the outer bound.
result = specSize;
} else if (specMode == MeasureSpec.EXACTLY){
// If your control can fit within these bounds return that value.
result = specSize;
}*/
return bg_on.getWidth();
}
}

代码比较简单,而且注释比较详细。

说一些几个问题:

1. onTouch()方法中得到的event.getX()和event.getY()是什么值?取值范围是多少?

刚开始我以为不管咱们的SlipButton放在什么位置,得到的event.getX()值因该是相对屏幕的坐标值,~~其实是错误的,event.getX()只有你的触摸点在当前SlipButton view的布局范围之内才会取到值的。但是值的范围可不仅仅是你的SlipButton view的大小哦,因为一旦你的触摸点在view范围之内触摸到,那么触摸点就可以移到View之外的任何地方了,所以取值范围应该是全屏哦,因此我们在代码里做了如下判断:

 if (event.getX() > bg_on.getWidth()
|| event.getY() > bg_on.getHeight()) {
return false;
}

2. measureWidth()和measureHeight()为什么会返回一个固定值?

首先根据用途,我们自定义的SlipButton View根本没有必要去由调用者调整大小,因为这个ToggleButton本身就是起到开关作用的,在应用中应该是一致的,所以我让这两个方法返回固定值。关于onMeasure()方法根详细的描述,请看我的另一篇文章:http://www.cnblogs.com/wlrhnh/p/3479928.html

下载源码,请猛戳这里。

可滑动的ToggleButton(开关)的更多相关文章

  1. ToggleButton开关状态按钮控件

    ToggleButton开关状态按钮控件 一.简介 1. 2.ToggleButton类结构 父类是CompoundButton,引包的时候注意下 二.ToggleButton开关状态按钮控件使用方法 ...

  2. OpenCV学习笔记——滑动条开关

    由于opencv库中并没有专门为开关而设的函数,可以用滑动条做开关 代码: #include<highgui.h> #include<cv.h> int g_switch_va ...

  3. iOS:步进UIStepper、滑动块UISlider、开关UISwitch的基本使用

    步进UIStepper.滑动块UISlider:当它们作为事件,被触发时,它们的值会发生改变.正因为如此,触发该事件时,可以一张一张翻阅浏览图片,,,, 步进UIStepper: @property( ...

  4. 绘制 ToggleButton --重写view

    package com.example.compoundbuttonview.view; import com.example.compoundbuttonview.R; import android ...

  5. 自定义View-6 状态按钮 滑动 点击

    View public class SwitchButton extends View implements OnClickListener, OnTouchListener {     privat ...

  6. iOS7下滑动返回与ScrollView共存二三事

    [转载请注明出处] = =不是整篇复制就算注明出处了亲... iOS7下滑动返回与ScrollView共存二三事 [前情回顾] 去年的时候,写了这篇帖子iOS7滑动返回.文中提到,对于多页面结构的应用 ...

  7. Ext 6.5.3 classic版本,自定义实现togglefield开关控件

    1,在Ext 6.5.3的classic版中没有提供开关控件,参照modern版中 togglefield开关的实现,继承滑动器(sliderfield),自定义一个开关按钮.支持value绑定和点击 ...

  8. Android控件ToggleButton的使用方法

    ToggleButton(开关button)是Android系统中比較简单的一个组件,是一个具有选中和未选择状态双状态的button.而且须要为不同的状态设置不同的显示文本. ToggleButton ...

  9. 转--2014年最新810多套android源码2.46GB免费一次性打包下载

    转载自:http://www.eoeandroid.com/thread-497046-1-1.html 感谢该博客主人无私奉献~~ 下面的源码是从今年3月份开始不断整理源码区和其他网站上的安卓例子源 ...

随机推荐

  1. (一)二维数组&&指针数组与数组指针

    一.首先我们从字面意思理解一下什么是指针数组什么是数组指针 1.指针数组:本质是一个数组,数组中的每一个元素是一个指针. 2.数组指针:本质是一个指针,而指针指向一个数组. 二.我们该怎么区分指针数组 ...

  2. 【Todo】蒙特卡洛(蒙特卡罗)树 & 卷积网络

    https://www.zhihu.com/question/41176911/answer/90066752 这里面有关于Deep Learning和蒙特卡洛树的一些内容 https://www.z ...

  3. mysql 命令行快速导出数据,导入数据

    如果数据有20几万以上的时候,下面的方法很实用 导出数据 1.into outfile select * from table into outfile 'C:/a.sql'; 2.mysqldump ...

  4. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)

    反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法)   创建Delegate (1).Delegate.CreateDelegate(Type, ...

  5. VB6 GDI+ 入门教程[2] GDI+初始化

    http://vistaswx.com/blog/article/category/tutorial/page/2 VB6 GDI+ 入门教程[2] GDI+初始化 2009 年 6 月 18 日 7 ...

  6. Element can be click when out of view

    WebDriver can't action the element when out of view Webdriver can't action the element when the elem ...

  7. 使用node js 操作 Mysql 数据库

    使用node js 操作 Mysql 数据库 http://www.nodejs.org/ //node js 数据库操作 MySQL //使用https://github.com/felixge/n ...

  8. mysql 免安装版本 命令安装

    1.down load mysql-5.5.28-win32.zip 2.unzip it to a path such as d:/mysq/mysql-5.5.28-win32 3.copy th ...

  9. noip2016题解汇总

    [uoj#260]玩具谜题 传送门 http://uoj.ac/problem/260 分析 模拟. int n,m; int dir[N]; char nam[N][L]; int a[M],s[M ...

  10. Linq分页查询

    //Linq分页查询 int pageIndex = Convert.ToInt32(HttpContext.Current.Request["PageIndex"]); int ...