开关按钮实现

1、原理和效果图

总共有两张图片,一张背景图片,一张遮罩图片。背景图片有开关字样,通过遮住一个字来实现开关按钮。继承自View控件,通过Canvas和Paint结合来实现图片的绘制。

通过canvas的drawBitmap方法和距离左边的位置来绘制图片,调用invalidate方法来不断的更新UI,就可以实现滑动的效果。

public class MyToggleButton extends View implements OnClickListener{
	/**
	 * 做为背景的图片
	 */
	private Bitmap backgroundBitmap;
	/**
	 * 可以滑动的图片
	 */
	private Bitmap slideBtn;
	private Paint paint;
	/**
	 * 滑动按钮的左边届
	 */
	private float slideBtn_left;
	/**
	 * 当前开关的状态
	 *  true 为开
	 */
	private boolean currState = false;
	/**
	 * 判断是否发生拖动,如果拖动了,就不再响应 onclick 事件
	 */
	private boolean isDrag = false;
	/**
	 * 在代码里面创建对象的时候,使用此构造方法
	 */
	public MyToggleButton(Context context) {
		super(context);
	}

	/**
	 * 在布局文件中声名的view,创建时由系统自动调用。
	 * @param context	上下文对象
	 * @param attrs		属性集
	 */
	public MyToggleButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}

	/**
	 * 初始化
	 */
	private void initView() {
		//初始化图片
		backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
		slideBtn = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
		//初始化 画笔
		paint = new Paint();
		paint.setAntiAlias(true); // 打开抗矩齿

		//添加onclick事件监听
		setOnClickListener(this);
	}

	/*
	 * view 对象显示的屏幕上,有几个重要步骤:
	 * 1、构造方法 创建 对象。
	 * 2、测量view的大小。	onMeasure(int,int);
	 * 3、确定view的位置 ,view自身有一些建议权,决定权在 父view手中。  onLayout();
	 * 4、绘制 view 的内容 。 onDraw(Canvas)
	 */

	/**
	 * 测量尺寸时的回调方法
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		/**
		 * 设置当前view的大小
		 * width  :view的宽度
		 * height :view的高度   (单位:像素)
		 */
		try {
			setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	/**
	 * 绘制当前view的内容
	 */
	protected void onDraw(Canvas canvas) {
//		super.onDraw(canvas);

		// 绘制 背景
		/*
		 * backgroundBitmap	要绘制的图片
		 * left	图片的左边届
		 * top	图片的上边届
		 * paint 绘制图片要使用的画笔
		 */
		canvas.drawBitmap(backgroundBitmap, 0, 0, paint);

		//绘制 可滑动的按钮
		canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
	}

	@Override
	/**
	 * onclick 事件在View.onTouchEvent 中被解析。
	 * 系统对onclick 事件的解析,过于简陋,只要有down 事件  up 事件,系统即认为 发生了click 事件
	 *
	 */
	public void onClick(View v) {
		if(!isDrag){ //如果没有拖动,才执行改变状态的动作
			currState = !currState;
			flushState();
		}
	}

	/**
	 * down 事件时的x值
	 */
	private int firstX;
	/**
	 * touch 事件的上一个x值
	 */
	private int lastX;

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			firstX = lastX =(int) event.getX();
			isDrag = false;
			break;
		case MotionEvent.ACTION_MOVE:
			//判断是否发生拖动
			if(Math.abs(event.getX()-firstX)>5){
				isDrag = true;
			}

			//计算 手指在屏幕上移动的距离
			int dis = (int) (event.getX() - lastX);

			//将本次的位置 设置给lastX
			lastX = (int) event.getX();

			//根据手指移动的距离,改变slideBtn_left 的值
			slideBtn_left = slideBtn_left+dis;
			break;
		case MotionEvent.ACTION_UP:
			//在发生拖动的情况下,根据最后的位置,判断当前开关的状态
			if (isDrag) {
				int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth(); // slideBtn左边届最大值
				/*
				 * 根据 slideBtn_left 判断,当前应是什么状态
				 */
				if (slideBtn_left > maxLeft / 2) { // 此时应为 打开的状态
					currState = true;
				} else {
					currState = false;
				}

				flushState();
			}
			break;
		}

		flushView();

		return true;
	}

	/**
	 * 刷新当前状态
	 */
	private void flushState() {
		if(currState){
			slideBtn_left = backgroundBitmap.getWidth()-slideBtn.getWidth();
		}else{
			slideBtn_left = 0;
		}
		mToggleSwitch.openOrClose(currState);
		flushView();
	}

	/**
	 * 刷新当前视力
	 */
	private void flushView() {
		//对 slideBtn_left  的值进行判断 ,确保其在合理的位置 即       0<=slideBtn_left <=  maxLeft
		int maxLeft = backgroundBitmap.getWidth()-slideBtn.getWidth();	//	slideBtn 左边届最大值

		//确保 slideBtn_left >= 0
		slideBtn_left = (slideBtn_left>0)?slideBtn_left:0;

		//确保 slideBtn_left <=maxLeft
		slideBtn_left = (slideBtn_left<maxLeft)?slideBtn_left:maxLeft;
		/*
		 * 刷新当前视图  导致 执行onDraw执行
		 */
		invalidate();
	}

	public void setmToggleSwitch(ToggleSwitch mToggleSwitch) {
		this.mToggleSwitch = mToggleSwitch;
	}

	private ToggleSwitch mToggleSwitch;

	public interface ToggleSwitch {
		/**
		 * true 为开 ,false 为关
		 * @param open
		 */
		public void openOrClose(boolean open);
	}
}

2、布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.MyToggleButton
        android:id="@+id/my_toggle_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
         />

</RelativeLayout>

3、调用

myToggleButton = (MyToggleButton) findViewById(R.id.my_toggle_btn);

		myToggleButton.setmToggleSwitch(new ToggleSwitch() {
			@Override
			public void openOrClose(boolean open) {
				if (open) {
					Toast.makeText(MainActivity.this, "打开", Toast.LENGTH_SHORT).show();
				}else {
					Toast.makeText(MainActivity.this, "关闭", Toast.LENGTH_SHORT).show();
				}
			}
		});
时间: 2024-11-25 08:28:58

开关按钮实现的相关文章

PyQt4开关按钮ToggleButton

PyQt4没有开关按钮部件.但是我们可以使用在特殊状态下的QPushButton部件来创建开关按钮.而所谓的开关按钮就是一个具有按下和未按下两种状态的普通赶牛.用户可以通过单击按钮来切换其开或者关的状态.在一些情形下,这个特性会非常好用. #!/usr/bin/python # -*- coding: utf-8 -*- import sys from PyQt4 import QtGui, QtCore class ToggleButton(QtGui.QWidget): def __init

Android——图片视图(ImageView)、状态开关按钮(ToggleButton)、时钟

xml <?xml version="1.0" encoding="utf-8"?> <!--滚动视图--> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_pare

控制控件(滑杆,分段选择控件,开关按钮)

// //  ViewController.m //  UI-NO-9 // //  Created by Bruce on 15/7/23. //  Copyright (c) 2015年 Bruce. All rights reserved. //   #import "ViewController.h"   @interface ViewController () {     UIView *bgView;     UIImageView *animationView; } @e

自定义控件(视图)28期笔记07:自定义控件之使用系统控件(自定义属性之开关按钮案例的优化)

1.先前,我们编好的开关按钮的项目工程,如下: 2. 下面我们要使用自定义的属性优化这个开关按钮,如下: (1)第1步,我们在res/values文件夹下,新建一个attrs.xml文件,如下: 其中attrs.xml,如下: 1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 <!-- 声明一个属性集的名称 --> 4 <declare-styleable na

Android动画:模拟开关按钮点击打开动画(属性动画之平移动画)

在Android里面,一些炫酷的动画确实是很吸引人的地方,让然看了就赏心悦目,一个好看的动画可能会提高用户对软件的使用率.另外说到动画,在Android里面支持两种动画:补间动画和属性动画,至于这两种动画的区别这里不再介绍,希望开发者都能在使用的过程中体会两者的不同. 本文使用属性动画完成,说到属性动画,肯定要提到 JakeWharton大神写的NineOldAndroids动画库,如果你的app需要在android3.0以下使用属性动画,那么这个库就很有作用了,如果只需要在高版本使用,那么直接

使用jQuery实现类似开关按钮的效果

转自:http://www.cnblogs.com/linjiqin/p/3148228.html 本案例实现类似开关按钮效果. 页面有下拉列表.文本框.按钮等表单元素,大致实现如下效果:1.页面一加载时,文本框隐藏,下拉列表显示,按钮值变为“显示文本框”.2.点击“显示文本框”按钮时,文本框显示,下拉列表隐藏,按钮值变为“显示下拉列表”.3.点击“显示下拉列表”按钮时,文本框隐藏,下拉列表显示,按钮值变为“显示文本框”. <!DOCTYPE HTML PUBLIC "-//W3C//DT

cocos2d-x 2.2.6 之CCControlSwitch开关按钮

感慨什么的不多说了,就是想创建声音,音效的开关按钮,可参考cocos2d-x的Demo代码,其文件为: CCControlSwitchTest.cpp. 我将其资源放置到本人Demo的资源目录中,其大概代码如下: .h文件 #include "cocos2d.h" #include "cocos-ext.h" USING_NS_CC; USING_NS_CC_EXT; // 声音音效的设定(仅写关键代码,且只写声音,其它的就不做编写了) class UISwitch

WINFORM 自定义开关按钮控件-

本文章转载:http://www.cnblogs.com/feiyangqingyun/archive/2013/06/15/3137597.html OK,大工告成,上图演示效果. 源码下载:http://files.cnblogs.com/feiyangqingyun/myButtonCheckTest.zip WINFORM 自定义开关按钮控件-,布布扣,bubuko.com

iOS开关按钮UISwitch控件

开关按钮UISwitch 在ViewController.h里面 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #import <UIKit/UIKit.h> @interface ViewController : UIViewController{   //定义一个开关控件   //作用可以进行状态的改变   //开,关:两种状态可以切换   //所有UIKit框架库中的控件均已UI开头   //苹果官方的控件都定义在UIKit框架库中   UISw

基于Bootstrap的jQuery开关按钮插件

    按钮 下载 使用方法 首先要在页面中引入依赖文件: jquery.Bootstrap.Bootstrap Switch CSS和Bootstrap Switch JS.这里用的是bootstrap2 <link href="bootstrap.css" rel="stylesheet"> <link href="bootstrap-switch.css" rel="stylesheet"> &l