~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46704745

介绍

昨天晚上写了一个Android的滑动开关, 即SlideSwitch。

效果例如以下:

实现

实现的思路事实上非常easy。监听控件上的touch事件,并不断刷新,让滑块在手指的位置上绘出,达到滑块跟着手指滑动的显示效果。

先看一下代码:

SlideSwitch.java (7月3日有改动:在touch事件里调用onStateChangedListener前添加判空)

package com.incell.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View; public class SlideSwitch extends View{ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗锯齿 boolean isOn = false;
float curX = 0;
float centerY; //y固定
float viewWidth;
float radius;
float lineStart; //直线段開始的位置(横坐标,即
float lineEnd; //直线段结束的位置(纵坐标
float lineWidth;
final int SCALE = 4; // 控件长度为滑动的圆的半径的倍数
OnStateChangedListener onStateChangedListener; public SlideSwitch(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public SlideSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
} public SlideSwitch(Context context) {
super(context);
} @Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
curX = event.getX();
if(event.getAction() == MotionEvent.ACTION_UP)
{
if(curX > viewWidth / 2)
{
curX = lineEnd;
if(false == isOn)
{
//仅仅有状态发生改变才调用回调函数, 下同
if(null != onStateChangedListener)
{
onStateChangedListener.onStateChanged(true);
}
isOn = true;
}
}
else
{
curX = lineStart;
if(true == isOn)
{
if(null != onStateChangedListener)
{
onStateChangedListener.onStateChanged(false);
}
isOn = false;
}
}
}
/*通过刷新调用onDraw*/
this.postInvalidate();
return true;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*保持宽是高的SCALE / 2倍, 即圆的直径*/
this.setMeasuredDimension(this.getMeasuredWidth(), this.getMeasuredWidth() * 2 / SCALE);
viewWidth = this.getMeasuredWidth();
radius = viewWidth / SCALE;
lineWidth = radius * 2f; //直线宽度等于滑块直径
curX = radius;
centerY = this.getMeasuredWidth() / SCALE; //centerY为高度的一半
lineStart = radius;
lineEnd = (SCALE - 1) * radius;
} @Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas); /*限制滑动范围*/
curX = curX > lineEnd?lineEnd:curX;
curX = curX < lineStart? lineStart:curX; /*划线*/
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(lineWidth);
/*左边部分的线,绿色*/
mPaint.setColor(Color.BLUE);
canvas.drawLine(lineStart, centerY, curX, centerY, mPaint);
/*右边部分的线,灰色*/
mPaint.setColor(Color.GRAY);
canvas.drawLine(curX, centerY, lineEnd, centerY, mPaint); /*画圆*/
/*画最左和最右的圆,直径为直线段宽度。 即在直线段两边分别再加上一个半圆*/
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.GRAY);
canvas.drawCircle(lineEnd, centerY, lineWidth / 2, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawCircle(lineStart, centerY, lineWidth / 2, mPaint);
/*圆形滑块*/
mPaint.setColor(Color.LTGRAY);
canvas.drawCircle(curX, centerY, radius , mPaint); }
/*设置开关状态改变监听器*/
public void setOnStateChangedListener(OnStateChangedListener o)
{
this.onStateChangedListener = o;
} /*内部接口。开关状态改变监听器*/
public interface OnStateChangedListener
{
public void onStateChanged(boolean state);
} }

凝视应该非常具体了。主要有下面几点。

1、重写了onMeasure方法,使控件高度依赖于控件的宽度

这样不论在布局文件里怎样设置。总能保证控件的宽高比

2、控制好滑块的活动范围

3、定义内部接口OnStateChangedListener,并在自己定义控件里定义了其对象以及从外部赋值的方法setOnStateChangedListener,以便对开关状态更改事件进行监听并调用回调

使用及Demo

在布局文件里加入该控件就可以使用。Demo效果为动图展示效果(demo里颜色为绿色,动图为蓝色是由于绿色会导致截取gif时出问题,暂时更改的)。

Demo中布局文件例如以下:

activity_main.xml:

<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" > <com.example.slideswitchexample.SlideSwitch
android:id="@+id/slide_switch"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/> </RelativeLayout>

Demo中Activity代码例如以下:

MainActivity.java

package com.example.slideswitchexample;

import com.example.slideswitchexample.SlideSwitch.OnStateChangedListener;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast; public class MainActivity extends Activity { SlideSwitch sSwitch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sSwitch = (SlideSwitch) this.findViewById(R.id.slide_switch);
sSwitch.setOnStateChangedListener(new OnStateChangedListener(){ @Override
public void onStateChanged(boolean state) {
// TODO Auto-generated method stub
if(true == state)
{
Toast.makeText(MainActivity.this, "开关已打开", 1000).show();
}
else
{
Toast.makeText(MainActivity.this, "开关已关闭", 1000).show();
}
} });
} }

点此下载Demoproject

【Android】自己定义控件实现可滑动的开关(switch)的更多相关文章

  1. Android自己定义控件系列五:自己定义绚丽水波纹效果

    尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自己定义控件实现一个比較有趣的效果 ...

  2. Android自己定义控件:进度条的四种实现方式

    前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源代码下载)http://down ...

  3. android 自己定义控件

    Android自己定义View实现非常easy 继承View,重写构造函数.onDraw.(onMeasure)等函数. 假设自己定义的View须要有自己定义的属性.须要在values下建立attrs ...

  4. Android自己定义控件皮肤

    Android自己定义控件皮肤 对于Android的自带控件,其外观仅仅能说中规中矩,而我们平时所示Android应用中,一个简单的button都做得十分美观.甚至于很多button在按下时的外观都有 ...

  5. android 自己定义控件属性(TypedArray以及attrs解释)

    近期在捣鼓android 自己定义控件属性,学到了TypedArray以及attrs.在这当中看了一篇大神博客Android 深入理解Android中的自己定义属性.我就更加深入学习力一番.我就沿着这 ...

  6. Android自己定义控件系列二:自己定义开关button(一)

    这一次我们将会实现一个完整纯粹的自己定义控件,而不是像之前的组合控件一样.拿系统的控件来实现.计划分为三部分:自己定义控件的基本部分,自己定义控件的触摸事件的处理和自己定义控件的自己定义属性: 以下就 ...

  7. Android自己定义控件之轮播图控件

    背景 近期要做一个轮播图的效果.网上看了几篇文章.基本上都能找到实现,效果还挺不错,可是在写的时候感觉每次都要单独去又一次在Activity里写一堆代码.于是自己封装了一下.这里仅仅是做了下封装成一个 ...

  8. Android自己定义控件系列三:自己定义开关button(二)

    接上一篇自己定义开关button(一)的内容继续.上一次实现了一个开关button的基本功能.即自己定义了一个控件.开关button,实现了点击切换开关状态的功能.今天我们想在此基础之上.进一步实现触 ...

  9. Android自己定义控件2-简单的写字板控件

    概述 上一篇文章我们对自己定义控件进行了一个大体的知识介绍. 今天就来学习自己定义一个简单的写字板控件. 先来看看效果图 就是简单的依据手指写下的轨迹去画出内容 实现 在上一篇文章里提到了androi ...

随机推荐

  1. 【贪心】【后缀自动机】Gym - 101466E - Text Editor

    题意:给你两个串A,B,以及一个整数K,让你找到B的一个尽可能长的前缀,使得其在A串中出现的次数不小于K次. 对A串建立后缀自动机,然后把B串放在上面跑,由于每到一个结点,该结点endpos集合的大小 ...

  2. 7.4 (java学习笔记)网络编程之TCP

    一.TCP 1.1 TCP(Transmission Control Protocol 传输控制协议),是一种面向连接的,安全的传输协议,但效率相比于UDP而言比较低. TCP传输时需要确保先建立连接 ...

  3. python开发_tkinter_菜单的不同选项

    python的tkinter模块中,菜单也可以由你自定义你的风格 下面是我做的demo 运行效果: ====================================== 代码部分: ===== ...

  4. Codeforces Round #295 (Div. 2)B - Two Buttons BFS

    B. Two Buttons time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  5. ASP.NET MVC 手机短信验证

    本文来自于stoneniqiu的文章,原文地址 http://www.cnblogs.com/stoneniqiu/p/6234002.html 1.注册一个应用 得到AppKey 和 App Sec ...

  6. c# 四舍五入、上取整、下取整

    在处理一些数据时,我们希望能用“四舍五入”法实现,但是C#采用的是“四舍六入五成双”的方法,如下面的例子,就是用“四舍六入五成双”得到的结果: double d1 = Math.Round(1.25, ...

  7. PHP自学之路---雇员管理系统(1)

    前面已经介绍了Zend studio工具的使用以及软件开发的基本阶段,下面就是我们第一个练习,雇员管理系统,从设计到实现来简单介绍下: 开发环境: 服务器:基于Linux 2.618环境下配置PHP服 ...

  8. __attribute__ ((attribute-list))

    http://blog.csdn.net/ithomer/article/details/6566739 构造与析构: #include <stdio.h> #include <st ...

  9. 多线程调试必杀技 - GDB的non-stop模式

     作者:破砂锅  (转) 开源的GDB被广泛使用在Linux.OSX.Unix和各种嵌入式系统(例如手机),这次它又带给我们一个惊喜. 多线程调试之痛 调试器(如VS2008和老版GDB)往往只支持a ...

  10. HDU5087 Revenge of LIS II (LIS变形)

    题目链接:pid=5087">http://acm.hdu.edu.cn/showproblem.php?pid=5087 题意: 求第二长的最长递增序列的长度 分析: 用step[i ...