平板升级之后,发现新的 IOS 系统中,上划之后出现的调节音量的控件让人看起来非常舒适,不错,尝试在Android 上实现以下。
上图:
第一步,画一个矩形。
第二步,在矩形上边画一个圆角矩形,通过
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
方法,使得两者重合的地方变成透明。
最终在代码中操纵第一次绘制的矩形,实现上图中的效果。
控件的扩展:
<attr name="bgColor" format="color|integer">attr>
<attr name="radius" format="integer">attr>
<attr name="isWrappeLine" format="boolean">attr>
在代码中,添加了
public void setValues(float v){
......
}
public IphoneSwitchView setColor(int color){
......
}
两个方法,使得我们可以去动态的修改控件的背景颜色。
还添加了一个回调,方便后续的开发工作。
public void registerCallback(ValueChangeCallback callback){
mCallback = callback;
}
interface ValueChangeCallback{
void onValueChanged(double value);
}
最后贴上关键代码:
public class IphoneSwitchView extends View{
private int mWidth,mHeight;
private int strokenWidth;
private boolean isWrapperLine;
private float lastX,lastY,curX,curY;
private int mCurrValue=100,mLastValue=0;
private int curPoint;
private int mBgColor;
private Paint paint;
private ValueChangeCallback mCallback;
public IphoneSwitchView(Context context) {
this(context,null);
}
public IphoneSwitchView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public IphoneSwitchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mWidth = getWidth();
mHeight = getHeight();
//初始化弧度大小
strokenWidth = strokenWidth!=-1?strokenWidth:mWidth/5;
}
private void init(Context context,AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.IphoneSwitchView);
int color = (int) array.getInt(R.styleable.IphoneSwitchView_bgColor,-1);
mBgColor = color!=-1?color:getResources().getColor(R.color.colorAccent);
strokenWidth = (int) array.getInt(R.styleable.IphoneSwitchView_radius,-1);
isWrapperLine = array.getBoolean(R.styleable.IphoneSwitchView_isWrappeLine,true);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(4);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制底部的矩形
RectF rectF = new RectF(0,mHeight-mCurrValue,mWidth,mHeight);
int layerId = canvas.saveLayer(0, 0, mWidth, mHeight, null, Canvas.ALL_SAVE_FLAG);
paint.setColor(mBgColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(rectF,paint);
// 开始绘制圆角矩形
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(strokenWidth);
rectF = new RectF(0,0,mWidth,mHeight);
canvas.drawRoundRect(rectF,strokenWidth,strokenWidth,paint);
paint.setXfermode(null);
canvas.restoreToCount(layerId);
// 判断是否需要外边框
if(isWrapperLine){
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
rectF = new RectF(1,1,mWidth-1,mHeight-1);
canvas.drawRoundRect(rectF,strokenWidth,strokenWidth,paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = event.getX();
lastY = event.getY();
//切记要进行事件拦截消费操作
return true;
case MotionEvent.ACTION_MOVE:
curX = event.getX();
curY = event.getY();
resetValues(lastY-curY);
lastX = event.getX();
lastY = event.getY();
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onTouchEvent(event);
}
private void resetValues(float v) {
float cacheValue = mCurrValue+v;
Log.d("chenxiaoping","v := "+v+" "+cacheValue+" mHeight "+mHeight);
if(cacheValue<=mHeight&&cacheValue>=0){
mCurrValue = (int) cacheValue;
if(mCallback!=null){
mCallback.onValueChanged(cacheValue/mHeight);
}
}
postInvalidate();
}
public void setValues(float v){
setInitialValue(v);
}
public IphoneSwitchView setColor(int color){
mBgColor = color;
postInvalidate();
return this;
}
/**
* persent 0-1
* @param value
* @return
*/
public IphoneSwitchView setInitialValue(double value){
if(value>1||value<0){
mCurrValue = 0;
}else{
mCurrValue = (int) (mHeight*value);
}
if(mCallback!=null){
mCallback.onValueChanged(mCurrValue/mHeight);
}
mLastValue = mCurrValue;
postInvalidate();
return this;
}
public void registerCallback(ValueChangeCallback callback){
mCallback = callback;
}
interface ValueChangeCallback{
void onValueChanged(double value);
}
}
介绍完毕,继续努力。