SwitchButton 开关按钮 的多种实现方式 (附源码DEMO)
http://blog.csdn.net/vipzjyno1/article/details/23707149
刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心。
所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果。
起初我在android上我只会使用CheckBox去满足对应的功能。后来,查看开发文档发现,android也有了自己的原生态开关控件,并且在4.0版本中又优化加入了新的类似控件--Switch控件,以及使用起来十分简单的ToggleButton,可是它们只是带有切换效果,而不带有滑动切换效果,并且Switch控件只支持高版本的系统,对于2.3就不支持。所以,要想看如何实现滑动切换的效果,必须了解这些控件的实现方式。下面,让我们查看下android开发文档,看看这些是如何实现使用的。
注意:本文中涉及到自定义控件 并自定义配置属性declare-styleable,
如果你对于自定义控件的自定义配置属性还不是很了解可以看:android 自定义控件 使用declare-styleable进行配置属性(源码角度)
查看查看开发文档:
CompoundButton
extends Button implements Checkable
↳ |
||||
|
↳ |
|||
|
|
↳ |
||
|
|
|
↳ |
android.widget.CompoundButton |
Known Direct Subclasses |
以上4类都是开关类型切换的控件,它们的父类都是CompoundButton。
它对应的方法和类有:
点击选择监听接口。
Nested Classes |
||
interface |
Interface definition for a callback to be invoked when the checked state of a compound button changed. |
返回左右填充的VIEW,加上间隔
Public Methods |
|
int |
getCompoundPaddingLeft()Returns the left padding of the view, plus space for the left Drawable if any. |
int |
getCompoundPaddingRight()Returns the right padding of the view, plus space for the right Drawable if any. |
boolean:是否被选中。
boolean |
设置Button的Drawable属性
void |
setButtonDrawable(int resid)Set the background to a given Drawable, identified by its resource id. |
设置是否选中
void |
setChecked(boolean checked)Changes the checked state of this button. |
改变当前的状态,true-->false ;false-->true
void |
toggle()Change the checked state of the view to the inverse of its current state |
控件全局 绘制
void |
protected void onDraw (Canvas canvas)
实现你自己的绘制。
参数
canvas 在画布上绘制背景
protected boolean verifyDrawable (Drawable who)
如果你的视图子类显示他自己的可视化对象,他将要重写此方法并且为了显示可绘制返回true。此操作允许进行绘制时有动画效果。
确认当重写从方法时,需调用父类相应方法。
参数
who 需判断的可绘制对象(Drawable)。如果是你要显示的对象,返回True,否则返回调用父类的结果。
返回值
boolean 如果可绘制对象(Drawable)已经在视图中显示,返回True否则返回false。并且此处不允许使用动画。
下面让我们来看看如何实现这个效果把:
一.使用ToggleButton控件实现:
使用ToggleButton控件十分方便,你可以看作他为一个CheckBox,只用设置它的button、background等几个属性即可。
首先:res--创建drawable文件夹 -- 创建switch_btn.xml资源文件--作以下配置
- <?xml version="1.0" encoding="utf-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:drawable="@drawable/ios7_switch_on" />
- <item android:drawable="@drawable/ios7_switch_off" />
- </selector>
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/ios7_switch_on" />
<item android:drawable="@drawable/ios7_switch_off" />
</selector>
其中:android:state_checked="true" 表示选中on时候的,效果为:android:drawable="@drawable/ios7_switch_on"
反之就是未选中off情况下的效果:android:drawable="@drawable/ios7_switch_off"
之后在布局文件中写控件:
- <ToggleButton
- android:id="@+id/mTogBtn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:background="@android:color/transparent"
- android:button="@drawable/toggle_btn"
- android:checked="false"
- android:text=""
- android:textOff=""
- android:textOn="" />
<ToggleButton
android:id="@+id/mTogBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@android:color/transparent"
android:button="@drawable/toggle_btn"
android:checked="false"
android:text=""
android:textOff=""
android:textOn="" />
这里的
android:textOn="" 表示:选中情况下显示的文本
android:textOff="" 表示:未选中情况下显示的文本
android:checked="false" 表示:初始化时候,默认是未选中的
android:button="@drawable/toggle_btn" 表示:button样式
android:background="@android:color/transparent" 表示:背景,这里不用它的默认背景,所以设置为透明
之后在主程序中实例化,并设置checked点击监听
- ToggleButton mTogBtn = (ToggleButton) findViewById(R.id.mTogBtn); // 获取到控件
- mTogBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
- // TODO Auto-generated method stub
- if(isChecked){
- //选中
- }else{
- //未选中
- }
- }
- });// 添加监听事件
ToggleButton mTogBtn = (ToggleButton) findViewById(R.id.mTogBtn); // 获取到控件
mTogBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
// TODO Auto-generated method stub
if(isChecked){
//选中
}else{
//未选中
}
}
});// 添加监听事件
这样ToggleButton的开关切换就轻松实现了。
二.重写CompoundButton控件实现带滑动效果的开关按钮:
重写CompuundButton的实现可能会显得相对繁琐些,主要是考虑状态是否已经选中等情况的文字显示。
可以查看官方文档,之后继承CompuundButton,在布局的动画和显示上调用onDraw(Canvas canvas)重画既可以,如果想要加入拖动属性,那么在该VIEW内重写触摸事件onTouchEvent(MotionEvent ev)在里面判断拖动距离,之后根据拖动情况判断开关是on还是off。
由于继承的是CompoundButton,所以里面的监听方法,setChecked等方法都是自带的,继承下来写操作就可以了,不用自己在去加判断什么的属性了。
由于DEMO中的继承CompoundButton的SwitchButton是使用自定义配置的,所以如果不了解自定义配置的可以看以下文章:android 自定义控件 使用declare-styleable进行配置属性(源码角度)
具体的这边不贴代码了,可以查看DEMO里面的,都有注释。
三.重写CheckBox控件实现带滑动效果的开关按钮:
其实,看上面给的开发文档内容,大家都可以知道,CheckBox其实就是继承CompoundButton控件的,只是重构CheckBox会比CompoundButton方便好多,里面的很多方法都是写好的,只要自己去判断触摸事件onTouchEvent(MotionEvent ev),以及onDraw(Canvas canvas)重画就可以。这里DEMO中使用到的是第3放库内的一个控件,大致操作和上面其实大同小异。
四.重写View实现带滑动效果的开关按钮:
众所周知,以上所有的控件都是继承了View这个父类,所以,如果你用View去操作的话,就没有自带方法的限制,可是要满足你要 实现的SwitchButton效果,你必须自己写开关状态监听接口,并且自己写setChecked方法实现同等的效果。在优化方面要自己多加细心考虑。其他操作与以上控件的重构大同小异。
注意:由于状态切换等,enabled属性改变等,是你自定义的方法内的话,你必须自己去调用invalidate();方法,去让UI判断是否有更改并做出相应的变化。
例如:
- @Override
- public void setEnabled(boolean enabled) {
- // TODO Auto-generated method stub
- mEnabled = enabled;
- mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
- Log.d("enabled",enabled ? "true": "false");
- super.setEnabled(enabled);
- invalidate();
- }
- /** 自动判断切换至相反的属性 : true -->false ;false -->true */
- public void toggle() {
- setChecked(!mSwitchOn);
- }
- /** 设置选中的状态(选中:true 非选中: false) */
- public void setChecked(boolean checked) {
- mSwitchOn = checked;
- invalidate();
- }
@Override
public void setEnabled(boolean enabled) {
// TODO Auto-generated method stub
mEnabled = enabled;
mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
Log.d("enabled",enabled ? "true": "false");
super.setEnabled(enabled);
invalidate();
} /** 自动判断切换至相反的属性 : true -->false ;false -->true */
public void toggle() {
setChecked(!mSwitchOn);
} /** 设置选中的状态(选中:true 非选中: false) */
public void setChecked(boolean checked) {
mSwitchOn = checked;
invalidate();
}
还有,你如果是自定义的VIEW,你在里面设置了enabled属性,你必须在onTouchEvent(MotionEvent event)触摸操作的时候判断你所设置的enabled属性是否为true,是的话就可以相应点击事件,否则的话你要屏蔽掉点击事件。因为你自定义的view中的enabled属性并不知道他设定后会达到什么效果,这些都是要注意的点。
还有就是要设置接口监听状态变化:
- /**
- * 设置 switch 状态监听
- * */
- public void setOnChangeListener(OnSwitchChangedListener listener) {
- switchListener = listener;
- }
- /**
- * switch 开关监听接口
- * */
- public interface OnSwitchChangedListener{
- public void onSwitchChange(SlideSwitchView switchView, boolean isChecked);
- }
/**
* 设置 switch 状态监听
* */
public void setOnChangeListener(OnSwitchChangedListener listener) {
switchListener = listener;
}
/**
* switch 开关监听接口
* */
public interface OnSwitchChangedListener{
public void onSwitchChange(SlideSwitchView switchView, boolean isChecked);
}
有的人可能会希望有SwitchButton在enabled设置为false的时候,SwitchButton不能点击且要改变颜色,使他看过去是不能点击的。你可以进行如下操作(在学习别的人代码中得到的提示,学以致用):
先初始化透明度:255为不透明
- /** 最大透明度,就是不透明 */
- private final int MAX_ALPHA = 255;
- /** 当前透明度,这里主要用于如果控件的enable属性为false时候设置半透明 ,即不可以点击 */
- private int mAlpha = MAX_ALPHA;
/** 最大透明度,就是不透明 */
private final int MAX_ALPHA = 255;
/** 当前透明度,这里主要用于如果控件的enable属性为false时候设置半透明 ,即不可以点击 */
private int mAlpha = MAX_ALPHA;
之后重写setEnabled方法,通过这个方法判断enabled属性值
- @Override
- public void setEnabled(boolean enabled) {
- // TODO Auto-generated method stub
- mEnabled = enabled;
- mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
- super.setEnabled(enabled);
- invalidate();
- }
@Override
public void setEnabled(boolean enabled) {
// TODO Auto-generated method stub
mEnabled = enabled;
mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
super.setEnabled(enabled);
invalidate();
}
如果改变了enabled属性,系统便会查看UI是否需要变化,之后在UI方法onDraw(Canvas canvas)中调用:
- android.graphics.Canvas.saveLayerAlpha(RectF bounds, int alpha, int saveFlags)
android.graphics.Canvas.saveLayerAlpha(RectF bounds, int alpha, int saveFlags)
方法,其中的第2个属性alpha就是透明度,之后便可以实现相应的效果。
由于目前对于重写VIEW的onDraw方法的了解不是很深入,所以这里的DEMO中的几个方法都是查看网络之后加上自己的优化和注释演变过来,等这一块深入了后在重写写一篇关于这个的感受和使用说明。由于可能理解不是很深刻,如果有什么不足之处可以提出,谢谢。
最后让我们来看看效果如何,上图:
最后上源码DEMO:下载地址
SwitchButton 开关按钮 的多种实现方式 (附源码DEMO)的更多相关文章
- SwitchButton 开关按钮 的多种实现方式
刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心. 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果. 起初我在android上我只会 ...
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按 ...
- Android 仿 新闻阅读器 菜单弹出效果(附源码DEMO)
这一系列博文都是:(android高仿系列)今日头条 --新闻阅读器 (一) 开发中碰到问题之后实现的,觉得可能有的开发者用的到或则希望独立成一个小功能DEMO,所以就放出来这么一个DEMO. 原本觉 ...
- 【网站国际化必备】Asp.Net MVC 集成Paypal(贝宝)快速结账 支付接口 ,附源码demo
开篇先给大家讲段历史故事,博主是湖北襄阳人.襄阳物华天宝,人杰地灵,曾用名襄樊.在2800多年的历史文化中出现了一代名相诸葛亮(卧龙),三国名士庞统(凤雏),魏晋隐士司马徽(水镜先生),唐代大诗人孟浩 ...
- 如何0代码实现多人音视频通话?【内附源码/Demo】
3月15日新增"1860+1194",全国进入了抗疫关键时期.响应政策多地采取了社会面清零策略. 3月14日零点,深圳按下了暂停键. 应疫情防控要求,深圳全市暂停生产经营活动,严格 ...
- spring学习笔记2---MVC处理器映射(handlerMapping)三种方式(附源码)
一.根据Beanname访问controller: 在springmmvc-servlet.xml的配置handlermapping中加入beanname,通过该beanname找到对应的contro ...
- swfupload多文件上传[附源码]
swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...
- 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生
[转].NET(C#):浅谈程序集清单资源和RESX资源 目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...
- 日志组件Log2Net的介绍和使用(附源码开源地址)
Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...
随机推荐
- Unity3d之树木创建的参数设定
Unity3d之树木创建的参数设定 通常Unity3d创建树木经常会创建出很多奇葩的种类=_=,以下是创建出比较正常树木的基本参数 1:> 基本树干形状建立: 选择根建立分枝干设置分支干Di ...
- 2.RapidIO串行物理层的包与控制符号
转自https://www.cnblogs.com/liujinggang/p/9932150.html 一.RapidIO串行物理层背景介绍 上篇博文提到RapidIO的物理层支持串行物理层与并行物 ...
- 《RabbitMQ Tutorial》译文 第 1 章 简介
原文来自 RabbitMQ 英文官网的教程(1.Introduction),其示例代码采用了 .NET C# 语言. RabbitMQ is a message broker: it accepts ...
- easyUI中textbox或number的数值大小校验
例:textbox里面,要求做两个textbox名字为(A,B),其中两个的数字大小范围是-10~10之间,之后其中A的值必须大于B所填的数字,如果输入错误,则提示出弹出框,并清空数据. <!D ...
- SQL中常用函数
SELECT CONVERT(varchar(100), GETDATE(), 23) AS 日期 结果:2017-01-05 select ISNULL(price,'0.0') ...
- np.array与np.ndarray区别
(Numpy中ndarray和array的区别是什么?我在哪儿能够找到numpy中相应的实现?) 答:Well, np.array is just a convenience function to ...
- java数值运算后精度丢失问题
最近连续俩次遇到运算后数值精度丢失问题,所以记录一下. 问题1:java计算百分比,应该得到57,可返回的就是56 在java代码中 BigDecimal progress; BigDecimal a ...
- jupyter notebook远程配置
服务器端配置 在服务器生成jupyter配置文件 $jupyter notebook --generate-config 生成之后会得到配置文件的路径 启动jupyter,设置密码 In [1]: f ...
- vue为app做h5页面,如何做到同域名对应不同版本的h5代码
1.当我们在做混合开发的时候,app端可以有无数多个版本,一般情况h5页面只有一套代码.应该如何部署多套代码呢? 2.业务场景 当出现这种情况的时候,其实前端可以部署多套代码.比如: www.stat ...
- mysql 和php 保留2位小数
一般交易中保留的数字的小数位数为2位(即最小单位为 1分钱[0.01元]) 数据库设计中预金钱有关或要求精准度要高的用 decimal(n,m) 表示,n表示保留的数字长度,保留的小数位数,如deci ...