这篇文章来介绍这两天的成果,android自带的switchbutton太难看了,于是照着ios的switchbutton做了一个高仿的自定义switchbutton,目前还不是很完美,代码也还比较乱,但还是分享出来,望大家指教!
先看效果图(不知道怎么搞gif图片,就先勉强看下好了,也希望会录制gif图的大神指导下)
首先来讲一下实现的大致流程:首先这个控件继承自view实现,在onlayout或者onWindowFocuschanged方法中去获取height和width,依此确定一些属性的大小,比如滑动的圆圈的半径,确定属性之后再创建一个ShapeDrawable(也就是中间滑动的小球),然后在创建一个小的圆角矩形(仔细观察ios的switchbutton你就会发现里面有个小的圆角矩形)
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if(isFirst){
final int width = getWidth();
final int height = getHeight();
radius = Math.min(width, height) * 0.5f;
spotSize = height - 2 * borderWidth;
float spotR = spotSize * 0.5f;
spotMinX = 2 * borderWidth;
spotMaxX = width - height;
spotX = toggleOn ? spotMaxX : spotMinX;
// 创建一个圆
OvalShape circle = new OvalShape();
// 设置该椭圆的宽、高
circle.resize(spotSize, spotSize);
// 将圆包装成Drawable对象
ShapeDrawable drawable = new ShapeDrawable(circle);
ss = new SqqShape(drawable);
ss.setX(spotX);
ss.setY(centerY);
Paint paints = drawable.getPaint();
paints.setColor(spotColor);
// 创建小圆角矩形
float radiu = spotR;
float[] out = {radiu,radiu,radiu,radiu,radiu,radiu,radiu,radiu};
RoundRectShape recta = new RoundRectShape(out, null, null);
if(toggleOn){
recta.resize(0, 0);
}else{
recta.resize(width- 4 * borderWidth, height - 2 * borderWidth);
}
ShapeDrawable background = new ShapeDrawable(recta);
bb = new SqqShape(background);
bb.setX(borderWidth * 2);
bb.setY(borderWidth);
bb.setColor(closeColor);
bb.setWidth(width- 4 * borderWidth);
bb.setHeight(height - 2 * borderWidth);
isFirst = false;
}
}
public class SqqShape {
private float x = 0, y = 0;
private ShapeDrawable shape;
private int color;
private float width,height;
public SqqShape(ShapeDrawable s)
{
shape = s;
}
public float getX()
{
return x;
}
public void setX(float x)
{
this.x = x;
}
public float getY()
{
return y;
}
public void setY(float y)
{
this.y = y;
}
public ShapeDrawable getShape()
{
return shape;
}
public void setShape(ShapeDrawable shape)
{
this.shape = shape;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public void setScale(float x){
Shape s = shape.getShape();
shape.setBounds(0,(int)(height-height*x)/2,(int)(width*x),(int)(height*x));
Log.d("sqq", "width: "+width+" height:"+height);
//s.resize(x*width, s.getHeight());
}
}
private void SpringAnim(float startX,float endX){
if(mCuranim !=null){
mCuranim.cancel();
}
ObjectAnimator alpAnim = null;
if (!toggleOn) {
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scale",
0f, 1f);
alpAnim= ObjectAnimator.ofPropertyValuesHolder(bb,pvhY);
alpAnim.addUpdateListener(this);
}
if(startX!=endX){
float back = (float) (0.05*(startX-endX));
/**
* 小球滑到目标位置的动画
*/
ObjectAnimator sAnim = ObjectAnimator.ofFloat(ss, "x",
startX, endX-back);
// 设置sAnim动画的插值方式:加速插值
sAnim.setInterpolator(new AccelerateInterpolator());
sAnim.setDuration(120);
sAnim.addUpdateListener(this);
/**
* 小球弹到最终位置
*/
ObjectAnimator springAnim1 = ObjectAnimator.ofFloat(ss, "x",
endX-back,endX);
springAnim1.setInterpolator(new DecelerateInterpolator());
springAnim1.addUpdateListener(this);
// 定义一个AnimatorSet1来组合动画
AnimatorSet animatorSet = new AnimatorSet();
AnimatorSet animatorSet1 = new AnimatorSet();
// 指定在播放springAnim1之前,先播放sAnim动画
if(alpAnim !=null){
animatorSet1.play(springAnim1).with(alpAnim);
animatorSet1.setDuration(160);
animatorSet.play(sAnim).before(animatorSet1);
}else{
animatorSet.play(sAnim).before(springAnim1);
}
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCuranim = null;
super.onAnimationEnd(animation);
}
@Override
public void onAnimationCancel(Animator animation) {
mCuranim = null;
super.onAnimationCancel(animation);
}
});
// 开发播放动画
animatorSet.start();
mCuranim = animatorSet;
}else{
if(alpAnim!=null)
alpAnim.start();
}
}
@Override
protected void onDraw(Canvas canvas) {
/**
* 颜色改变部分
*/
if(toggleOn){
borderColor = onColor;
}else{
borderColor = offBorderColor;
}
Paint paint;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Style.FILL);
paint.setStrokeCap(Cap.ROUND);
rect.set(0, 0, getWidth(), getHeight());
paint.setColor(borderColor);
canvas.drawRoundRect(rect, radius, radius, paint);
canvas.save();
canvas.translate(bb.getX(), bb.getY());
Paint pain = bb.getShape().getPaint();
pain.setColor(bb.getColor());
bb.getShape().draw(canvas);
canvas.restore();
canvas.save();
canvas.translate(ss.getX(), ss.getY());
ss.getShape().draw(canvas);
// 恢复Canvas坐标系统
canvas.restore();
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float deltaX = Math.abs(x - mFirstDownX);
float deltaY = Math.abs(y - mFirstDownY);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mFirstDownX = x;
mFirstDownY = y;
ChangeCBAnim();
break;
case MotionEvent.ACTION_MOVE:
float offset = x-mFirstDownX;
float finalx = ss.getX()+offset/8;
if(finalxspotMaxX){
finalx = spotMaxX;
}
ss.setX(finalx);
break;
case MotionEvent.ACTION_UP:
if (deltaX == 0 || deltaY == 0 || deltaX > mTouchSlop) {
if (deltaX > mTouchSlop) {
if (ss.getX() > mTouchSlop) {
toggleOn = true;
} else {
toggleOn = false;
}
}
if(deltaX == 0 || deltaY == 0){
toggleOn = !toggleOn;
}
SpringAnim(ss.getX(), toggleOn ? spotMaxX
: spotMinX);
if (listener != null) {
listener.onToggle(toggleOn);
}
}
break;
default:
break;
}
invalidate();
return true;
}
其实最主要的就只是几个属性动画,其他也没什么好讲的,如果对属性动画不是那么了解可以去看我的另一篇文章http://blog.csdn.net/u012806692/article/details/50944606
源码:http://download.csdn.net/detail/u012806692/9453035