又畫了一個圓,但此次這個帶了個觸摸,因爲最近在搞智能家居類應用,因此可想而知有不少東西須要自定義如遙控器,調節器,還有一些帶動畫效果的View,畢竟叫智能產品嘛,不能就是開和關兩個選項加一些圖片吧,因此仍是要自定義一些控件的,今天這個是一個環形調節期,能夠適應於空調或者熱水器的遠程調節控件,咱們主要是用於設備的調檔。android
上次的寫的一個控件 炫酷的空氣淨化器控件 : AirPurgeLayoutViewgit
- 背光燈漸變
- 背光燈調色
- 控制環的顏色
- 控制環形的度數
- 平滑實現調節
- 裏面因此參數均可以微調
這裏說的背光燈效果是第二個圓環的陰影背景這裏實現仍是很是簡單的,但須要主要一下記得關閉硬件加速,要否則就沒有效果了。github
private void onStartBacklightAnim() {
if (mBacklightAnim != null && mBacklightAnim.isRunning()) {
return;
}
mBacklightAnim = ObjectAnimator.ofFloat(this,"curShadowRadius",0,mSecondCircleShadowRadius);
mBacklightAnim.setDuration(mBacklightAnimDurtion);
mBacklightAnim.setRepeatCount(ValueAnimator.INFINITE);
mBacklightAnim.setRepeatMode(ValueAnimator.REVERSE);
mBacklightAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mCurShadowRadius = mSecondCircleShadowRadius;
}
});
mBacklightAnim.start();
}
複製代碼
這個實現也挺簡單的若是你知道android自定義view有三種經常使用漸變方法這個一看就知道(1. LinearGradient 線性漸變 2.RadialGradient 輻射漸變 3.SweepGradient 環形漸變)其實還有一些但這三個比較經常使用不知道的google一下或者看下官網就ok了,這裏用到的是SweepGradient 但有一個問題就是他是360°的顏色從0度開始到最後不能調節顏色開始角度,因此使用時最好在首位加多加一位顏色。canvas
//繪製顏色
if (mColors != null && mColors.length != 0) {
canvas.save();
canvas.rotate(90, mCenterX, mCenterY);
if (mColors.length == 1) {
mPaint.setColor(mColors[0]);
} else if (mColors.length>1) {
SweepGradient sweepGradient = new SweepGradient(mCenterX, mCenterY, mColors, null);
mPaint.setShader(sweepGradient);
![sweep.gif](http://upload-images.jianshu.io/upload_images/2646598-5d1fbd181e0411b6.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
}
canvas.drawArc(rectF, (360 - mThreeRingAngle) / 2, mThreeRingAngle, false, mPaint);
mPaint.setShader(null);
canvas.restore();
}
複製代碼
實現滑動控制主要是監聽下view的onTouchEvent方法,這裏主要控件的邏輯大體是,當用戶手指按下這個控件時會判斷是否單機控件的第三個控制圓環,若是有出發控制,若是沒有不處理觸摸。api
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isForbidSlide) return false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onStopAutoFlingAnim(); //有動畫馬上中止
boolean isTakeOver = isTakeOverTouch(event.getX(),event.getY()); //第一次單機在圓環上才接管觸摸
if (isTakeOver) {
mPreX = (int) event.getX();
mPreY = (int) event.getY();
refreshAngle(mPreX,mPreY,true);
return true;
} else {
return false;
}
case MotionEvent.ACTION_MOVE:
refreshAngle((int) event.getX(),(int) event.getY(),false);
break;
case MotionEvent.ACTION_UP:
break;
}
return true; //consumption
}
/**
* 判斷是否接管觸摸 兩種狀況
*/
private boolean isTakeOverTouch(float downX,float downY) {
//加個0.5防止有些人眼神或手很差點不到圓弧上
float minRadius = mThreeCircleRadius - mThreeCircleWidth/2f - 0.5f;
float maxRadius = mThreeCircleRadius + mThreeCircleWidth/2f + 0.5f;
//到按下點到圓心的距離
float distanceCircle = (float) Math.abs(Math.sqrt((downX-mCenterX)*(downX-mCenterX)+(downY-mCenterY)*(downY-mCenterY)));
if (distanceCircle >= minRadius && distanceCircle <= maxRadius) {
if (mThreeRingAngle > 180 && downY > mCenterY) {
float angle = (float) (Math.atan(Math.abs(downX-mCenterX)/Math.abs(downY-mCenterY))*180/Math.PI);
if ((360-mThreeRingAngle)/2f > angle) {
return false;
}
} else if (mThreeRingAngle <= 180) {
if (downY>mCenterY) {
return false;
} else {
float angle = (float) (Math.atan(Math.abs(downX-mCenterX)/Math.abs(downY-mCenterY))*180/Math.PI);
if (angle > (360-mThreeRingAngle)/2f) {
return false;
}
}
}
return true;
}
return false;
}
複製代碼
這個也很簡單主要是現實根據進度實現動畫性的改變進度,但須要注意的是當觸摸時馬上中止動畫,若是動畫在運行的。bash
private ValueAnimator mAutoFlingAnim;
public void setCurAngle(float progress,boolean isWantAnim) {
if (isWantAnim) {
if (mAutoFlingAnim != null && mAutoFlingAnim.isRunning()) {
mAutoFlingAnim.cancel();
mAutoFlingAnim.removeAllUpdateListeners();
mAutoFlingAnim = null;
}
mAutoFlingAnim = new ValueAnimator();
float curProgress = ((mCurAngle+90+mThreeRingAngle/2f)%360)/mThreeRingAngle;
mAutoFlingAnim.setFloatValues(curProgress,progress);
mAutoFlingAnim.setDuration((long) (Math.abs(progress-curProgress)*2000));
mAutoFlingAnim.setInterpolator(new LinearInterpolator());
mAutoFlingAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = (float) valueAnimator.getAnimatedValue();
int angle = (int) (value*mThreeRingAngle + (360-mThreeRingAngle)/2f+90)%360;
if (mCurAngle != angle) {
mCurAngle = angle;
invalidate();
}
}
});
mAutoFlingAnim.start();
} else {
this.mCurAngle = (int) (progress*mThreeRingAngle + (360-mThreeRingAngle)/2f+90)%360;
invalidate();
}
}
複製代碼
最近開發智能家居產品,須要時不時定義一些view,但若是你完整的看完過android view的api時,你會發現其實真的不難,不少google都給你封裝好了,像什麼漸變啊,貝塞爾曲線,圖片剪切,動畫,觸摸滑動,佈局填充等,你只要學會拼接就能夠,因此若是項目須要大量使用自定義控件的能夠去系統的看一遍view的api。ide