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

介绍

昨天晚上写了一个Android的滑动开关, 即SlideSwitch。效果如下:

实现

实现的思路其实很简单,监听控件上的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:

"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"/>

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();                }            }        });    }}

点此下载Demo工程

更多相关文章

  1. android:沉浸式状态栏(状态栏一体化)
  2. Android之PopupWindow弹出对话框
  3. Android(安卓)控件之Spinner
  4. Android(安卓)Permission
  5. Android(安卓)控件之TextView常见使用问题
  6. Eclipse下使用Android(安卓)Design Support Library中的控件
  7. 浅谈Android中的BaseAdpater
  8. 在Android(安卓)Studio 中使用ADB命令模拟手机各种状态(记录中...
  9. android 加载网络图片 SkImageDecoder::Factory returned null

随机推荐

  1. 【译】Android(安卓)Bluetooth
  2. ANDRIOD学习笔记之nand、root以及主要调
  3. 去除启动edittext时候默认的焦点
  4. Android实例剖析笔记(八)
  5. EventBus 和RxLifecycle 一起使用所引发
  6. Android电子书阅读器的设计与实现
  7. 深入解读Linux与Android的相互关系& Andr
  8. 2011.09.09 ——— android 2.2 修改安装
  9. android模拟器大幅优化_android开发者的
  10. Android 使用非阻塞的方式读写串口