绘制 ToggleButton --重写view
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的更多相关文章
- Android 自定义View 三板斧之三——重写View来实现全新控件
通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文来讨论最难的一种 ...
- 128、View 绘制流程 & 自定义View
记清楚函数调用的顺序才能准确地进行调用. 根据调用链,可将整个绘制过程分为三部分:Measure - Layout - Draw Measure 过程 1. 测量过程由上至下,在measure过程的最 ...
- Android重写view时onAttachedToWindow () 和 onDetachedFromWindow ()
在重写View的时候,会遇到这两个方法 protected void onAttachedToWindow() Description copied from class: View This is ...
- android重写view和viewgroup的区别
重写view: View类一般用于绘图操作,重写它的onDraw方法,但它不可以包含其他组件,没有addView(View view)方法. 重写viewgroup: ViewGroup是一个组件容器 ...
- 绘制圆动画--重写view
/** * @FileName CircleProgressBar.java * @Package com.read.view * @Description TODO * @Author Alpha ...
- 重写 View 的 Touch 方法,实现一个酷炫的九宫格图片
前几天翻看代码库,发现一个之前写过的一个有意思的小玩意,共享给大家
- Android应用层View绘制流程与源码分析
1 背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...
- 自定义View_1_关于View,ViewGroup的测量和绘制流程
自定义View(1) ------ 关于View,ViewGroup的测量和绘制流程 在Android当中,自定义控件属于比较高级的知识体系,今天我们就一起研究研究关于自定义View的那点事,看看它到 ...
- Android view的测量及绘制
讲真,自我感觉,我的水平真的是渣的一匹,好多东西都只停留在知道和会用的阶段,也想去研究原理和底层的实现,可是一看到代码就懵逼了,然后就看不下去了, 说自己不着急都是骗人的,我自己都不信,前两天买了本& ...
随机推荐
- 排列组合算法(PHP)
用php实现的排列组合算法.使用递归算法,效率低,胜在简单易懂.可对付元素不多的情况. //从$input数组中取$m个数的组合算法 function comb($input, $m) { if($m ...
- .NET环境下导出Excel表格的两种方式和导入两种类型的Excel表格
一.导出Excel表格的两种方式,其中两种方式指的是导出XML数据类型的Excel(即保存的时候可以只需要修改扩展名为.xls)和真正的Excel这两种. using System; using Sy ...
- mysql命令化操作实用小技巧
★1.问:如果我的mysql数据库服务器程序在D:\program files\phpstudy\mysql,里,那么我该怎么在cmd命令状态下使用它? 进入cmd状态后,系统默认在当前用户 ...
- Swift让编程更简单 人人都是开发者
全称为苹果全球开发者大会的WWDC,每年的这个时候,都会如这段时间前后所举行的Google I/O 和微软的BUILD开发者会议一样,吸引全球科技媒体的目光.近几年来,因为在会上爆的猛料越来越多,“开 ...
- [转]Oracle VM VirtualBox虚拟机,Ubuntu虚拟机共享文件夹
VirtualBox的菜单里选择"设备" -> "安装增强功能...". "设备" -> "共享文档夹",添 ...
- java jinfo命令详解
jinfo (configuration info): 功能:输出Java进程的系统信息与jvm参数. 摘要: jinfo [ option ] pid jinfo [ option ] execut ...
- pthread——pthread_cleanup
Pthread_cleanup用于注册线程清理函数,注册的清理函数将在线程被取消或者主动调用pthread_exit时被调用: 一个简单的示例: #include <pthread.h& ...
- HK一行所见闻
香港一行 20多年来,未未去过HK,前段时间由于工作关系去了趟HK.感触良多. 一清早,福田过关,做火车,做地铁,一通到了目的地. 总结对那边的印象: 1,所有人都是粤语,包括工作交流.而且他们不怎么 ...
- Vmware配置
1.网络 四种连接模式的区别:http://www.cnblogs.com/awpatp/archive/2009/07/24/1530471.html 如果网卡使用Nat模式,则需要启动服务: VM ...
- 一次与51aspx客服MM谈话 -- 坑是怎么发展的
GG从发布以来,我每次版本更新都会同步到51aspx源码网站,这次在同步更新GG V3.2版本到51aspx时,出了点小状况: 上传3.2版本几个小时后,我再次上去查看,发现其状态变成了“退回”,于是 ...