这篇文章来介绍这两天的成果,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(finalx<spotMinX){ finalx = spotMinX; } if(finalx>spotMaxX){ 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