个人觉得5.0以后原生的switch样式不错,但是5.0以下的版本却不能用,再加上本身这个控件有bug(滑到中间就停起了,看图2。。。fuck),以前也用过第三方的switchbutton但是个人觉得很麻烦,要添加图片,还要增加自定义属性等。于是小弟决定自己写一个,本着“懒不惊人死不休”的精神用纯代码来实现。只需要这一个SwitchButton.java文件即可,方便快捷。当然也可以增加自定义属性。
可以通过setXXX的方法来更改一些属性。
水平有限,不喜勿喷
直接上图:上面的是自定义,下面是官方的
代码如下:
package com.sly.view;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.ImageButton;
/**
* 自定义SwitchButton(仿Android 5.0自带)
*
* @author HeyGays
*
*/
public class SwitchButton extends ImageButton {
private final int ROUND_MARGIN = 2;// 圆点按钮的外边距dp,避免圆点边缘被遮盖
private Paint paint;// 画圆点的笔
private boolean isOn;// 开关状态,左关右开
private float touchX = 0;// 手指按下的x坐标
private int touchSlop;// 最小滑动距离
private int backHeight = 24;// 背景默认高度dp
private int backWidth;// 背景宽度dp
private int backPadding = 5;// 背景的默认padding dp
private int backColor_Off = Color.GRAY;// 背景的默认填充颜色
private int backColor_On = Color.DKGRAY;// 背景的默认填充颜色
private int backRoundRadius = backHeight;// 背景的默认圆角半径dp
private int m = 0;// 相对于最左的位移距离 dp
private int m_Max;// m的最大坐标
private int round_Size;// 圆点的大小
private GradientDrawable gd;// 背景drawble
private RectF roundBtnRect = new RectF();// 圆点所在矩形范围
public SwitchButton(Context context) {
this(context, null);
}
public SwitchButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwitchButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initSize();
initBack();
initPaint();
}
/**
* 初始化一些尺寸
*/
private void initSize() {
touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
// 根据高度计算圆点大小
round_Size = backHeight - 2 * ROUND_MARGIN;
// 根据圆点大小计算开关宽度
backWidth = 2 * (round_Size + ROUND_MARGIN);
// 根据宽度计算最大位移坐标
m_Max = backWidth - ROUND_MARGIN - round_Size - 1;
}
/**
* 初始化背景
*/
private void initBack() {
int padding = dp2px(backPadding);
gd = new GradientDrawable();
gd.setColor(backColor_Off);
gd.setCornerRadius(dp2px(backRoundRadius));
if (padding == 0) {// 防止黑边
gd.setStroke(padding, Color.TRANSPARENT);
}
setPadding(padding, padding, padding, padding);
setImageDrawable(gd);
}
/**
* 初始化画笔
*/
private void initPaint() {
setLayerType(LAYER_TYPE_SOFTWARE, null);// 关闭硬件加速
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.LTGRAY);
paint.setStyle(Style.FILL_AND_STROKE);
paint.setShadowLayer(2, 0, 2, Color.DKGRAY);
paint.setStrokeWidth(1);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(dp2px(backWidth), dp2px(backHeight));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
roundBtnRect.left = dp2px(ROUND_MARGIN + m);
roundBtnRect.top = dp2px(ROUND_MARGIN);
roundBtnRect.right = roundBtnRect.left + dp2px(round_Size);
roundBtnRect.bottom = roundBtnRect.top + dp2px(round_Size);
canvas.drawArc(roundBtnRect, 0, 360, false, paint);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
getParent().requestDisallowInterceptTouchEvent(true);
if (Math.abs(event.getX() - touchX) > touchSlop) {
int moveX = (int) (event.getX() - touchX);
if (isOn) {
if (moveX <= 0) {
m = m_Max + (moveX / 3) < 0 ? 0 : m_Max + (moveX / 3);// 按钮的滑动速度等于手指的1/3
} else {
m = m_Max;
}
} else {
if (moveX >= 0) {
m = (moveX / 3) >= m_Max ? m_Max : moveX / 3;
} else {
m = 0;
}
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (Math.abs(event.getX() - touchX) > touchSlop) {
if (m > m_Max / 2) {
isOn = false;
} else {
isOn = true;
}
}
move();
break;
}
return true;
}
/**
* 移动动画
*/
private void move() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
post(new Runnable() {
@Override
public void run() {
if (!isOn) {
m++;
} else {
m--;
}
if (m >= m_Max) {
m = m_Max;
isOn = true;
gd.setColor(backColor_On);
setImageDrawable(gd);
removeCallbacks(this);
cancel();
} else if (m <= 0) {
m = 0;
isOn = false;
gd.setColor(backColor_Off);
setImageDrawable(gd);
removeCallbacks(this);
cancel();
}
invalidate();
}
});
}
}, 0, 10);
}
/**
* dip转为 px
*/
public int dp2px(int dipValue) {
float scale = getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
/**
* 设置圆点的颜色
*
* @param roundBtnColor
*/
public void setRoundBtnColor(int roundBtnColor) {
paint.setColor(roundBtnColor);
invalidate();
}
/**
* 设置背景高度
*
* @param backHeight
*/
public void setBackHeight(int backHeight) {
this.backHeight = backHeight < this.backHeight ? this.backHeight : backHeight;
initSize();
}
/**
* 设置背景padding
*
* @param backPadding
*/
public void setBackPadding(int backPadding) {
if (backPadding <= 0) {
backPadding = 0;
}
if (backPadding > backHeight) {
backPadding = this.backPadding;
}
this.backPadding = backPadding;
initBack();
}
/**
* 设置关闭的背景颜色
*
* @param backColor_On
*/
public void setBackColorWithOff(int backColor_Off) {
this.backColor_Off = backColor_Off;
initBack();
}
/**
* 设置打开的背景颜色
*
* @param backColor_On
*/
public void setBackColorWithOn(int backColor_On) {
this.backColor_On = backColor_On;
initBack();
}
/**
* 返回开关状态
*
* @return
*/
public boolean isOn() {
return isOn;
}
}