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

java.lang.Object

android.view.View

 

android.widget.TextView

 

 

android.widget.Button

 

 

 

android.widget.CompoundButton

Known Direct Subclasses

CheckBox,RadioButton,Switch,ToggleButton

以上4类都是开关类型切换的控件,它们的父类都是CompoundButton。

它对应的方法和类有:

点击选择监听接口。

Nested Classes

interface

CompoundButton.OnCheckedChangeListener

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

isChecked()

设置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

onDraw(Canvas canvas)Implement this to do your drawing.

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资源文件--作以下配置

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <selector
  3. xmlns:android="http://schemas.android.com/apk/res/android">
  4. <item android:state_checked="true" android:drawable="@drawable/ios7_switch_on" />
  5. <item android:drawable="@drawable/ios7_switch_off" />
  6. </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"

之后在布局文件中写控件:

  1. <ToggleButton
  2. android:id="@+id/mTogBtn"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:layout_gravity="center_horizontal"
  6. android:background="@android:color/transparent"
  7. android:button="@drawable/toggle_btn"
  8. android:checked="false"
  9. android:text=""
  10. android:textOff=""
  11. 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点击监听

  1. ToggleButton mTogBtn = (ToggleButton) findViewById(R.id.mTogBtn); // 获取到控件
  2. mTogBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {
  3. @Override
  4. public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
  5. // TODO Auto-generated method stub
  6. if(isChecked){
  7. //选中
  8. }else{
  9. //未选中
  10. }
  11. }
  12. });// 添加监听事件
	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判断是否有更改并做出相应的变化。

例如:

  1. @Override
  2. public void setEnabled(boolean enabled) {
  3. // TODO Auto-generated method stub
  4. mEnabled = enabled;
  5. mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
  6. Log.d("enabled",enabled ? "true": "false");
  7. super.setEnabled(enabled);
  8. invalidate();
  9. }
  10. /** 自动判断切换至相反的属性 : true -->false ;false -->true */
  11. public void toggle() {
  12. setChecked(!mSwitchOn);
  13. }
  14. /** 设置选中的状态(选中:true   非选中: false) */
  15. public void setChecked(boolean checked) {
  16. mSwitchOn = checked;
  17. invalidate();
  18. }
	@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属性并不知道他设定后会达到什么效果,这些都是要注意的点。

还有就是要设置接口监听状态变化:

  1. /**
  2. * 设置 switch 状态监听
  3. * */
  4. public void setOnChangeListener(OnSwitchChangedListener listener) {
  5. switchListener = listener;
  6. }
  7. /**
  8. * switch 开关监听接口
  9. *  */
  10. public interface OnSwitchChangedListener{
  11. public void onSwitchChange(SlideSwitchView switchView, boolean isChecked);
  12. }
	/**
* 设置 switch 状态监听
* */
public void setOnChangeListener(OnSwitchChangedListener listener) {
switchListener = listener;
}
/**
* switch 开关监听接口
* */
public interface OnSwitchChangedListener{
public void onSwitchChange(SlideSwitchView switchView, boolean isChecked);
}

有的人可能会希望有SwitchButton在enabled设置为false的时候,SwitchButton不能点击且要改变颜色,使他看过去是不能点击的。你可以进行如下操作(在学习别的人代码中得到的提示,学以致用):

先初始化透明度:255为不透明

  1. /** 最大透明度,就是不透明 */
  2. private final int MAX_ALPHA = 255;
  3. /** 当前透明度,这里主要用于如果控件的enable属性为false时候设置半透明 ,即不可以点击 */
  4. private int mAlpha = MAX_ALPHA;
	/** 最大透明度,就是不透明 */
private final int MAX_ALPHA = 255;
/** 当前透明度,这里主要用于如果控件的enable属性为false时候设置半透明 ,即不可以点击 */
private int mAlpha = MAX_ALPHA;

之后重写setEnabled方法,通过这个方法判断enabled属性值

  1. @Override
  2. public void setEnabled(boolean enabled) {
  3. // TODO Auto-generated method stub
  4. mEnabled = enabled;
  5. mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
  6. super.setEnabled(enabled);
  7. invalidate();
  8. }
	@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)中调用:

  1. 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)的更多相关文章

  1. SwitchButton 开关按钮 的多种实现方式

    刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心. 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果. 起初我在android上我只会 ...

  2. Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO

    距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按 ...

  3. Android 仿 新闻阅读器 菜单弹出效果(附源码DEMO)

    这一系列博文都是:(android高仿系列)今日头条 --新闻阅读器 (一) 开发中碰到问题之后实现的,觉得可能有的开发者用的到或则希望独立成一个小功能DEMO,所以就放出来这么一个DEMO. 原本觉 ...

  4. 【网站国际化必备】Asp.Net MVC 集成Paypal(贝宝)快速结账 支付接口 ,附源码demo

    开篇先给大家讲段历史故事,博主是湖北襄阳人.襄阳物华天宝,人杰地灵,曾用名襄樊.在2800多年的历史文化中出现了一代名相诸葛亮(卧龙),三国名士庞统(凤雏),魏晋隐士司马徽(水镜先生),唐代大诗人孟浩 ...

  5. 如何0代码实现多人音视频通话?【内附源码/Demo】

    3月15日新增"1860+1194",全国进入了抗疫关键时期.响应政策多地采取了社会面清零策略. 3月14日零点,深圳按下了暂停键. 应疫情防控要求,深圳全市暂停生产经营活动,严格 ...

  6. spring学习笔记2---MVC处理器映射(handlerMapping)三种方式(附源码)

    一.根据Beanname访问controller: 在springmmvc-servlet.xml的配置handlermapping中加入beanname,通过该beanname找到对应的contro ...

  7. swfupload多文件上传[附源码]

    swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...

  8. 【转】.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 ...

  9. 日志组件Log2Net的介绍和使用(附源码开源地址)

    Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...

随机推荐

  1. Unity3d之树木创建的参数设定

    Unity3d之树木创建的参数设定 通常Unity3d创建树木经常会创建出很多奇葩的种类=_=,以下是创建出比较正常树木的基本参数 1:> 基本树干形状建立: 选择根建立分枝干设置分支干Di ...

  2. 2.RapidIO串行物理层的包与控制符号

    转自https://www.cnblogs.com/liujinggang/p/9932150.html 一.RapidIO串行物理层背景介绍 上篇博文提到RapidIO的物理层支持串行物理层与并行物 ...

  3. 《RabbitMQ Tutorial》译文 第 1 章 简介

    原文来自 RabbitMQ 英文官网的教程(1.Introduction),其示例代码采用了 .NET C# 语言. RabbitMQ is a message broker: it accepts ...

  4. easyUI中textbox或number的数值大小校验

    例:textbox里面,要求做两个textbox名字为(A,B),其中两个的数字大小范围是-10~10之间,之后其中A的值必须大于B所填的数字,如果输入错误,则提示出弹出框,并清空数据. <!D ...

  5. SQL中常用函数

    SELECT CONVERT(varchar(100), GETDATE(), 23) AS  日期   结果:2017-01-05     select ISNULL(price,'0.0')   ...

  6. np.array与np.ndarray区别

    (Numpy中ndarray和array的区别是什么?我在哪儿能够找到numpy中相应的实现?) 答:Well, np.array is just a convenience function to ...

  7. java数值运算后精度丢失问题

    最近连续俩次遇到运算后数值精度丢失问题,所以记录一下. 问题1:java计算百分比,应该得到57,可返回的就是56 在java代码中 BigDecimal progress; BigDecimal a ...

  8. jupyter notebook远程配置

    服务器端配置 在服务器生成jupyter配置文件 $jupyter notebook --generate-config 生成之后会得到配置文件的路径 启动jupyter,设置密码 In [1]: f ...

  9. vue为app做h5页面,如何做到同域名对应不同版本的h5代码

    1.当我们在做混合开发的时候,app端可以有无数多个版本,一般情况h5页面只有一套代码.应该如何部署多套代码呢? 2.业务场景 当出现这种情况的时候,其实前端可以部署多套代码.比如: www.stat ...

  10. mysql 和php 保留2位小数

    一般交易中保留的数字的小数位数为2位(即最小单位为 1分钱[0.01元]) 数据库设计中预金钱有关或要求精准度要高的用 decimal(n,m) 表示,n表示保留的数字长度,保留的小数位数,如deci ...