Android自己定义控件系列三:自己定义开关button(二)
接上一篇自己定义开关button(一)的内容继续。上一次实现了一个开关button的基本功能。即自己定义了一个控件。开关button,实现了点击切换开关状态的功能。今天我们想在此基础之上。进一步实现触摸拖拽开关滑块来实现开关的功能。还是一样先来看看效果,这里因为要显示拖拽。我打开了开发人员选项中的显示触摸操作,会在屏幕上显示一个圆圈表示触摸位置:
在这里,我们的主要工作就是在原有代码的基础上,添加一个重写的onTouchEvent方法。刚加入上来的时候是这个样子的:
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
对于触摸事件来说。一般返回值为true的话,那么就代表在这里消费掉本次触摸。而返回false的话,就在当前位置对本次触摸不做处理或者不能全然处理,还须要继续将本次事件分发给兴许view或者viewgroup响应,对于这里。我们定义的开关button已经是子view了。所以这里返回true就能够,如今看起来我们直接将return
super.onTouchEvent(event);这一句删掉。然后加上return true;就能够了,会不会产生什么问题呢?我们临时先这样处理。
之后的工作就比較简单了。我们须要依据event.getAction()的类型来做对应的处理,即我们基本上每天都在使用的:MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE和MotionEvent.ACTION_UP;
因为在ACTION_MOVE的时候。我们想让滑块随着我们手指的位置的移动而移动。这里因为仅仅是水平移动。所以我们仅仅须要记录x方向的位置,须要两个值:int
firstX和int secondX。firstX负责记录上一次ACTION_MOVE时候的x值,secondX负责记录本次ACTION_MOVE时候的x值。然后这两个值相减。则能够得到手指在两次ACTION_MOVE触发的时间里移动的距离。得到这个距离之后还须要将firstX调整为当前的值,以便下次使用。
然后将这个距离差值与我们滑块的位置进行求和。这样就能够调整我们滑块的位置随手指移动了。当然滑块的位置是有一个范围的,这里应该是[0,MAX_LEFT_DISTANCE],MAX_LEFT_DISTANCE
= backgroundBitmap.getWidth()- slideButton.getWidth();,所以我们须要做一个推断,来限制滑块,不让其划出边界。好了。基本逻辑到这里。看看代码:
@Override
public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN:
// 当按下的时候
firstX = secondX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
// 当移动的时候
// 计算手指在屏幕上移动的距离
int disX = (int) (event.getX() - secondX);
secondX = (int) event.getX(); // 将本次的位置。设置给lastX
slideBtn_left = slideBtn_left + disX; // 做一个推断,防止滑块划出边界,滑块的范围应该是在[0,MAX_LEFT_DISTANCE];
if (slideBtn_left < 0) {
slideBtn_left = 0;
} else {
if (slideBtn_left > MAX_LEFT_DISTANCE) {
slideBtn_left = MAX_LEFT_DISTANCE;
}
} break;
case MotionEvent.ACTION_UP:
// 当抬起的时候 // 抬起的时候,推断松开的位置是哪里,来由此来决定开关的状态是打开还是关闭
if (slideBtn_left < MAX_LEFT_DISTANCE / 2) {
currentState = false;
} else if (slideBtn_left >= MAX_LEFT_DISTANCE / 2) {
currentState = true;
} // 由开关的状态标志。确定应该是打开还是关闭状态
flushState();
break;
} // 依据状态标志来刷新相应的滑块停止位置,从而实现打开或者关闭效果
flushView(); // 返回true意味着消费掉本次事件。不让其它控件还能够接收到这个事件
return true;
}
写成如今这样会导致仅仅有拖动效果,而点击效果不起作用了。
。。
问题在哪里呢,实际上对于一个view来说。当点击事件传入的时候是先会调用onTouchEvent方法。然后才是调用onClick和onLongClick等方法。可是我们也没有看到这种方法里面可以怎样调用onClick方法啊?事实上,秘密就在我们之前删掉的return
super.onTouchEvent(event);这一句里面。
我们最好还是进入到super.onTouchEvent(event);里面一探到底,找到switch(event.getAction()){}这一块核心代码:
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
...
if (!post(mPerformClick)) {
performClick();
}
...
break;
case MotionEvent.ACTION_DOWN:
...
else {
// Not inside a scrolling container, so show the feedback right away
setPressed(true);
checkForLongClick(0);
}
...
break;
...
}
...
}
而在performClick()之中我们能够发现:
public boolean performClick() {
...
li.mOnClickListener.onClick(this);
...
}
到这里基本上就清楚了。onClick和onLongClick是在super.onTouchEvent方法里被调用的。onClick是在ACTION_UP的时候可能被调用。而onLongClick是在ACTION_DOWN的时候可能被调用。所以在这里我们尽管去掉了 return
super.onTouchEvent(event);这一句。可是super.onTouchEvent(event);是须要保留的。
我们能够将它放到onTouchEvent方法的第一句。
做完这一步之后我们会发现又能够响应到onClick方法了,可是还是有些不完美;我们希望在拖动之后就不要有点击操作。点击也不要有拖动效果(点击当然不会有拖动效果...),因为onClick点击的推断仅仅是单纯的检測ACTION_DOWN之后是否有一个ACTION_UP,假设有。那么就推断为一次点击事件,至于中间的过程是否滑动了,它却无论。所以在这里我们须要再加上一个boolean类型的推断标志isDrag。在ACTION_DOWN的时候将其设置为false,假设触发了ACTION_MOVE了,则将其置为true。
然后在onClick方法里面,加上一个条件。假设isDrag为假才运行点击的相应操作,否则就跳过。这样就比較完美了。
。。来看看终于的onTouchEvent和onClick的写法:
@Override
public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event);// 这一句不能少,否则无法触发onclick事件 switch (event.getAction()) { case MotionEvent.ACTION_DOWN:
// 当按下的时候
isDrag = false;
firstX = secondX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
// 当移动的时候
isDrag = true;
// 计算手指在屏幕上移动的距离
int disX = (int) (event.getX() - secondX);
secondX = (int) event.getX(); // 更新slideBtn_left的大小
slideBtn_left = slideBtn_left + disX; // 做一个推断。防止滑块划出边界,滑块的范围应该是在[0,MAX_LEFT_DISTANCE];
if (slideBtn_left < 0) {
slideBtn_left = 0;
} else {
if (slideBtn_left > MAX_LEFT_DISTANCE) {
slideBtn_left = MAX_LEFT_DISTANCE;
}
} break;
case MotionEvent.ACTION_UP:
// 当抬起的时候 // 抬起的时候,推断松开的位置是哪里,来由此来决定开关的状态是打开还是关闭
if (slideBtn_left < MAX_LEFT_DISTANCE / 2) {
currentState = false;
} else if (slideBtn_left >= MAX_LEFT_DISTANCE / 2) {
currentState = true;
} // 由开关的状态标志,确定应该是打开还是关闭状态
flushState();
break;
} // 依据状态标志来刷新相应的滑块停止位置。从而实现打开或者关闭效果
flushView(); // 返回true意味着消费掉本次事件,不让其它控件还能够接收到这个事件
return true;
}
@Override
public void onClick(View v) {
if (!isDrag) {
// 假设不是拖动事件。才进行点击事件的响应操作
currentState = !currentState;
flushState();
flushView();
} else {
// 假设是拖动事件,则不进行点击事件的响应操作
}
}
至此。关于自己定义开关的触摸事件就基本完毕了,事实上关于触摸点击的机制。Android是有一整套的流程的。。找时间会写一篇关于此的博文吧。
下一篇会解说怎样自己定义控件的自己定义属性。谢谢关注!
Android自己定义控件系列三:自己定义开关button(二)的更多相关文章
- Android自己定义控件系列五:自己定义绚丽水波纹效果
尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自己定义控件实现一个比較有趣的效果 ...
- Android自己定义控件系列案例【五】
案例效果: 案例分析: 在开发银行相关client的时候或者开发在线支付相关client的时候常常要求用户绑定银行卡,当中银行卡号一般须要空格分隔显示.最常见的就是每4位数以空格进行分隔.以方便用户实 ...
- Android自己定义控件系列二:自己定义开关button(一)
这一次我们将会实现一个完整纯粹的自己定义控件,而不是像之前的组合控件一样.拿系统的控件来实现.计划分为三部分:自己定义控件的基本部分,自己定义控件的触摸事件的处理和自己定义控件的自己定义属性: 以下就 ...
- Androd自己定义控件(三)飞翔的小火箭
在前面的自己定义控件概述中已经跟大家分享了Android开发其中自己定义控件的种类. 今天跟大家分享一个非主流的组合控件. 我们在开发其中,难免须要在不同的场合中反复使用一些控件的组合.而Java的最 ...
- 【Android】自己定义控件实现可滑动的开关(switch)
~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46704745 介绍 昨天晚上写了一个Android的滑动开关, 即SlideSwi ...
- android自己定义控件系列教程----视图
理解android视图 对于android设备我们所示区域事实上和它在底层的绘制有着非常大的关系,非常多时候我们都仅仅关心我们所示,那么在底层一点它究竟是怎么样的一个东西呢?让我们先来看看这个图. w ...
- android自己定义控件系列教程-----仿新版优酷评论剧集卡片滑动控件
我们先来看看优酷的控件是怎么回事? 仅仅响应最后也就是最顶部的卡片的点击事件,假设点击的不是最顶部的卡片那么就先把它放到最顶部.然后在移动到最前面来.重复如次. 知道了这几条那么我们就非常好做了. 里 ...
- android动手写控件系列——老猪叫你写相机
前记:Android这个开源而自由的系统,为我们带来开发便利,同时也埋下太多的深坑.例如调用系统自带的相机就会出现照片丢失,或者其他各种各样的问题.因此,看来自定义一个相机十分的必要. 要自定义相机我 ...
- Android自己定义控件系列一:Android怎样实现老版优酷client三级环形菜单
转载请附上本文链接:http://blog.csdn.net/cyp331203/article/details/40423727 先来看看效果: 一眼看上去好像还挺炫的,感觉比較复杂...实际上并不 ...
随机推荐
- Ubuntu搭建docker环境
一丶自己搭建Ubuntu的虚拟机(网上很多教程) PS:下带图形化界面的Ubuntu镜像,这里只说一下要装那些工具和做那些配置 安装vim sudo apt-get install ...
- Hadoop MapReduce编程 API入门系列之自定义多种输入格式数据类型和排序多种输出格式(十一)
推荐 MapReduce分析明星微博数据 http://git.oschina.net/ljc520313/codeexample/tree/master/bigdata/hadoop/mapredu ...
- 等等空格用法
平时经常用到 空格转移字符,记住一个 表示一个字符就可以了. Non-Breaking SPace 记住它是什么的缩写,更有助于我们记忆和使用.下面的字符转义自己视图翻译一下. 记录一下,空格的转 ...
- 打开word2010每次都要配置进度的解决办法
作者:朱金灿 来源:http://blog.csdn.net/clever101 不小心把ms office2010搞坏了,于是重装ms office2010,结果一打开word文档时总是出现下面的对 ...
- SQL Server将数据导出到SQL脚本文件
http://www.studyofnet.com/news/list-8883.2-1-4.html 一.SQL Server 2008将数据导出到SQL脚本文件 1.打开SQL Server200 ...
- linux openSSL 安装
包名:openssh-server apt安装:apt-get install openssh-server yum安装:yum install openssh-server 服务启动:service ...
- ubuntu安装-Caffe依赖
参考链接:http://my.oschina.net/u/939893/blog/163921 1. 安装numpy相对简单,以下命令可以完成 apt-get install python-numpy ...
- Qt5—嵌入停靠窗口QDockWidget
参考链接:http://blog.csdn.net/summer_xiyer/article/details/12875899 新建一个GUI工程: QDockWidget是QWidget的子类,也等 ...
- Kafka学习笔记(6)----Kafka使用Producer发送消息
1. Kafka的Producer 不论将kafka作为什么样的用途,都少不了的向Broker发送数据或接受数据,Producer就是用于向Kafka发送数据.如下: 2. 添加依赖 pom.xml文 ...
- Laravel 查询某天数据 whereDate