package com.example.compoundbuttonview.view;

import com.example.compoundbuttonview.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View; public class SlideSwitchView extends View{
/** Switch底部样式图片 */
private Bitmap mSwitchBottom;
/** Switch 当前样式 */
private Bitmap mSwitchThumb;
/** Switch无操作情况下的样式 */
private Bitmap mSwitchThumbNormal;
/** Switch当前手指触摸式的样式 */
private Bitmap mSwitchThumbPressed;
/** Switch 框架 */
private Bitmap mSwitchFrame;
private Bitmap mSwitchMask;
private float mCurrentX = 0;
/** Switch 开关状态,默认是 开:true */
private boolean mSwitchOn = true;
/** Switch 最大移动距离 */
private int mMoveLength;
/** 第一次按下的有效区域 */
private float mLastX = 0;
/** 绘制的目标区域大小 */
private Rect mDest = null;
/** 截取源图片的大小 */
private Rect mSrc = null;
/** Switch 移动的偏移量 */
private int mMoveDeltX = 0;
/** 画笔工具 */
private Paint mPaint = null;
/** Switch 状态监听接口 */
private OnSwitchChangedListener switchListener = null;
private boolean mFlag = false;
/** enabled 属性 为 true */
private boolean mEnabled = true;
/** 最大透明度,就是不透明 */
private final int MAX_ALPHA = 255;
/** 当前透明度,这里主要用于如果控件的enable属性为false时候设置半透明 ,即不可以点击 */
private int mAlpha = MAX_ALPHA;
/** Switch 判断是否在拖动 */
private boolean mIsScrolled =false; public SlideSwitchView(Context context) {
this(context, null);
} public SlideSwitchView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public SlideSwitchView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
} /**
* 初始化相关资源
*/
public void init() {
mSwitchThumbPressed = BitmapFactory.decodeResource(getResources(),R.drawable.checkswitch_btn_pressed);
mSwitchThumbNormal = BitmapFactory.decodeResource(getResources(),R.drawable.checkswitch_btn_unpressed);
mSwitchBottom = BitmapFactory.decodeResource(getResources(),R.drawable.checkswitch_bottom);
mSwitchFrame = BitmapFactory.decodeResource(getResources(),R.drawable.checkswitch_frame);
mSwitchMask = BitmapFactory.decodeResource(getResources(),R.drawable.checkswitch_mask);
mSwitchThumb = mSwitchThumbNormal;
mMoveLength = mSwitchBottom.getWidth() - mSwitchFrame.getWidth();
//绘制区域大小
mDest = new Rect(0, 0, mSwitchFrame.getWidth(),mSwitchFrame.getHeight());
mSrc = new Rect();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setAlpha(255);
//mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
setMeasuredDimension(mSwitchFrame.getWidth(), mSwitchFrame.getHeight());
} @Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (mMoveDeltX > 0 || mMoveDeltX == 0 && mSwitchOn) {
if (mSrc != null) {
mSrc.set(mMoveLength - mMoveDeltX, 0, mSwitchBottom.getWidth()
- mMoveDeltX, mSwitchFrame.getHeight());
}
} else if (mMoveDeltX < 0 || mMoveDeltX == 0 && !mSwitchOn) {
if (mSrc != null) {
mSrc.set(-mMoveDeltX, 0, mSwitchFrame.getWidth() - mMoveDeltX,
mSwitchFrame.getHeight());
}
}
Log.d("mAlpha", "mAlpha:" + mAlpha);
//绘制一个不透明矩形 为白色 和黑色底衬 成灰色
canvas.saveLayerAlpha(new RectF(mDest), mAlpha, Canvas.MATRIX_SAVE_FLAG
| Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
canvas.drawBitmap(mSwitchBottom, mSrc, mDest, null);
canvas.drawBitmap(mSwitchThumb, mSrc, mDest, null);
canvas.drawBitmap(mSwitchFrame, 0, 0, null);
canvas.drawBitmap(mSwitchMask, 0, 0, mPaint);
canvas.restore();
} @Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
//如果Enabled属性设定为true,触摸效果才有效
if(!mEnabled){
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mSwitchThumb = mSwitchThumbPressed;
mLastX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
mCurrentX = event.getX();
mMoveDeltX = (int) (mCurrentX - mLastX);
if(mMoveDeltX > 10){
//设置了10这个误差距离,可以更好的实现点击效果
mIsScrolled = true;
}
// 如果开关开着向左滑动,或者开关关着向右滑动(这时候是不需要处理的)
if ((mSwitchOn && mMoveDeltX < 0) || (!mSwitchOn && mMoveDeltX > 0)) {
mFlag = true;
mMoveDeltX = 0;
} if (Math.abs(mMoveDeltX) > mMoveLength) {
mMoveDeltX = mMoveDeltX > 0 ? mMoveLength : -mMoveLength;
}
invalidate();
break;
case MotionEvent.ACTION_UP:
mSwitchThumb = mSwitchThumbNormal;
//如果没有滑动过,就看作一次点击事件
if(!mIsScrolled){
mMoveDeltX = mSwitchOn ? mMoveLength : -mMoveLength;
mSwitchOn = !mSwitchOn;
if (switchListener != null) {
switchListener.onSwitchChange(this, mSwitchOn);
}
invalidate();
mMoveDeltX = 0;
break;
}
mIsScrolled = false;
if (Math.abs(mMoveDeltX) > 0 && Math.abs(mMoveDeltX) < mMoveLength / 2) {
mMoveDeltX = 0;
invalidate();
} else if (Math.abs(mMoveDeltX) > mMoveLength / 2
&& Math.abs(mMoveDeltX) <= mMoveLength) {
mMoveDeltX = mMoveDeltX > 0 ? mMoveLength : -mMoveLength;
mSwitchOn = !mSwitchOn;
if (switchListener != null) {
switchListener.onSwitchChange(this, mSwitchOn);
}
invalidate();
mMoveDeltX = 0;
} else if (mMoveDeltX == 0 && mFlag) {
// 这时候得到的是不需要进行处理的,因为已经move过了
mMoveDeltX = 0;
mFlag = false;
}
default:
break;
}
invalidate();
return true;
}
/**
* 设置 switch 状态监听
* */
public void setOnChangeListener(OnSwitchChangedListener listener) {
switchListener = listener;
}
/**
* switch 开关监听接口
* */
public interface OnSwitchChangedListener{
public void onSwitchChange(SlideSwitchView switchView, boolean isChecked);
} @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();
}
}

绘制 ToggleButton --重写view的更多相关文章

  1. Android 自定义View 三板斧之三——重写View来实现全新控件

    通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文来讨论最难的一种 ...

  2. 128、View 绘制流程 & 自定义View

    记清楚函数调用的顺序才能准确地进行调用. 根据调用链,可将整个绘制过程分为三部分:Measure - Layout - Draw Measure 过程 1. 测量过程由上至下,在measure过程的最 ...

  3. Android重写view时onAttachedToWindow () 和 onDetachedFromWindow ()

    在重写View的时候,会遇到这两个方法 protected void onAttachedToWindow() Description copied from class: View This is ...

  4. android重写view和viewgroup的区别

    重写view: View类一般用于绘图操作,重写它的onDraw方法,但它不可以包含其他组件,没有addView(View view)方法. 重写viewgroup: ViewGroup是一个组件容器 ...

  5. 绘制圆动画--重写view

    /** * @FileName CircleProgressBar.java * @Package com.read.view * @Description TODO * @Author Alpha ...

  6. 重写 View 的 Touch 方法,实现一个酷炫的九宫格图片

    前几天翻看代码库,发现一个之前写过的一个有意思的小玩意,共享给大家

  7. Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  8. 自定义View_1_关于View,ViewGroup的测量和绘制流程

    自定义View(1) ------ 关于View,ViewGroup的测量和绘制流程 在Android当中,自定义控件属于比较高级的知识体系,今天我们就一起研究研究关于自定义View的那点事,看看它到 ...

  9. Android view的测量及绘制

    讲真,自我感觉,我的水平真的是渣的一匹,好多东西都只停留在知道和会用的阶段,也想去研究原理和底层的实现,可是一看到代码就懵逼了,然后就看不下去了, 说自己不着急都是骗人的,我自己都不信,前两天买了本& ...

随机推荐

  1. 如何判断UIPanGestureRecognizer的拖动方向

    最近做一个项目,需要用到UIPanGestureRecognizer做一个侧滑菜单,需求是不能向右侧拖动(点击按钮右滑),但可以向左侧手势拖动收回:于是需要判断拖动的方向,百度了一下,网上大部分的答案 ...

  2. Oracle Blob 字段的模糊查询

    原文地址:http://blog.csdn.net/springk/article/details/6866248

  3. iOS 笔记

    1. 使用断言NSAssert()调试程序错误 NSAssert()只是一个宏,用于开发阶段调试程序中的Bug,通过为NSAssert()传递条件表达式来断定是否属于Bug,满足条件返回真值,程序继续 ...

  4. 深入理解Ember-Data特性(上)

    写在前面 最近比较忙,换了新工作还要学习很多全新的技术栈,并给自己找了很多借口来不去坚持写博客.常常具有讽刺意味的是,更多剩下的时间并没有利用而更多的是白白浪费,也许这就是青春吧,挥霍吧,这不是我想要 ...

  5. MySql学习(MariaDb)

    资料 http://www.cnblogs.com/lyhabc/p/3691555.html http://www.cnblogs.com/lyhabc/p/3691555.html MariaDb ...

  6. 如何自行处理写好的eclipse插件安装不生效

    本帖最后由 anrainie 于 2013-7-23 11:31 编辑 对于eclipse插件开发的新手,经常会遇到插件写好了,拷贝到plugins或dropins文件下,但是没有生效.上网各种问,也 ...

  7. Linux 网络编程(TCP)

    客户端代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/sock ...

  8. WPF,Silverlight与XAML读书笔记第四十三 - 多媒体支持之文本与文档

    说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. Glyphs对象(WPF,Silverlig ...

  9. Nim教程【十四】

    网友@沉没捕鱼,赞助了一台服务器 这个系列的教程写完之后,我们就要开始着手搭建Nim的社区了~ 异常 Nim中的异常类型是对象类型 根据惯例,Nim中的异常类型的命名都应该以Error后缀结尾 在sy ...

  10. 【译】用jQuery 处理XML-- jQuery与XML

    用jQuery 处理XML--写在前面的话 用jQuery 处理XML-- DOM(文本对象模型)简介 用jQuery 处理XML--浏览器中的XML与JavaScript 用jQuery 处理XML ...