又畫了一個(gè)圓骑丸,但這次這個(gè)帶了個(gè)觸摸,由于最近在搞智能家居類應(yīng)用恭取,所以可想而知有很多東西需要自定義如遙控器泰偿,調(diào)節(jié)器,還有一些帶動(dòng)畫效果的View蜈垮,畢竟叫智能產(chǎn)品嘛耗跛,不能就是開和關(guān)兩個(gè)選項(xiàng)加一些圖片吧,所以還是要自定義一些控件的攒发,今天這個(gè)是一個(gè)環(huán)形調(diào)節(jié)期调塌,可以適應(yīng)于空調(diào)或者熱水器的遠(yuǎn)程調(diào)節(jié)控件,我們主要是用于設(shè)備的調(diào)檔惠猿。
上次的寫的一個(gè)控件 炫酷的空氣凈化器控件 : AirPurgeLayoutView
1.主要功能
- 背光燈漸變
- 背光燈調(diào)色
- 控制環(huán)的顏色
- 控制環(huán)形的度數(shù)
- 平滑實(shí)現(xiàn)調(diào)節(jié)
- 里面所以參數(shù)都可以微調(diào)
2.背光燈效果
這里說的背光燈效果是第二個(gè)圓環(huán)的陰影背景這里實(shí)現(xiàn)還是非常簡單的羔砾,但需要主要一下記得關(guān)閉硬件加速,要不然就沒有效果了。
- setLayerType(LAYER_TYPE_SOFTWARE, null); //要關(guān)閉硬件加速
- mPaint.setShadowLayer(mCurShadowRadius, 0, 0, mSecondCircleShadowColor); //設(shè)置圓環(huán)陰影
- 實(shí)現(xiàn)動(dòng)畫效果
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();
}
3.實(shí)現(xiàn)外圓環(huán)環(huán)形漸變
這個(gè)實(shí)現(xiàn)也挺簡單的如果你知道android自定義view有三種常用漸變方法這個(gè)一看就知道(1. LinearGradient 線性漸變 2.RadialGradient 輻射漸變 3.SweepGradient 環(huán)形漸變)其實(shí)還有一些但這三個(gè)比較常用不知道的google一下或者看下官網(wǎng)就ok了,這里用到的是SweepGradient 但有一個(gè)問題就是他是360°的顏色從0度開始到最后不能調(diào)節(jié)顏色開始角度姜凄,所以使用時(shí)最好在首位加多加一位顏色政溃。
//繪制顏色
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();
}
4. 滑動(dòng)控制
實(shí)現(xiàn)滑動(dòng)控制主要是監(jiān)聽下view的onTouchEvent方法,這里主要控件的邏輯大致是态秧,當(dāng)用戶手指按下這個(gè)控件時(shí)會(huì)判斷是否單機(jī)控件的第三個(gè)控制圓環(huán)董虱,如果有出發(fā)控制,如果沒有不處理觸摸申鱼。
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isForbidSlide) return false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onStopAutoFlingAnim(); //有動(dòng)畫立刻停止
boolean isTakeOver = isTakeOverTouch(event.getX(),event.getY()); //第一次單機(jī)在圓環(huán)上才接管觸摸
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) {
//加個(gè)0.5防止有些人眼神或手不好點(diǎn)不到圓弧上
float minRadius = mThreeCircleRadius - mThreeCircleWidth/2f - 0.5f;
float maxRadius = mThreeCircleRadius + mThreeCircleWidth/2f + 0.5f;
//到按下點(diǎn)到圓心的距離
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;
}
5.實(shí)現(xiàn)代碼滑動(dòng)
這個(gè)也很簡單主要是現(xiàn)實(shí)根據(jù)進(jìn)度實(shí)現(xiàn)動(dòng)畫性的改變進(jìn)度愤诱,但需要注意的是當(dāng)觸摸時(shí)立刻停止動(dòng)畫,如果動(dòng)畫在運(yùn)行的捐友。
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();
}
}
6.感想
最近開發(fā)智能家居產(chǎn)品淫半,需要時(shí)不時(shí)定義一些view,但如果你完整的看完過android view的api時(shí)匣砖,你會(huì)發(fā)現(xiàn)其實(shí)真的不難撮慨,很多google都給你封裝好了,像什么漸變啊脆粥,貝塞爾曲線砌溺,圖片剪切,動(dòng)畫变隔,觸摸滑動(dòng)规伐,布局填充等,你只要學(xué)會(huì)拼接就可以匣缘,所以如果項(xiàng)目需要大量使用自定義控件的可以去系統(tǒng)的看一遍view的api猖闪。