炫酷的環形調節器控制元件 : RegulatorView

mochixuan發表於2017-12-04

又畫了一個圓,但這次這個帶了個觸控,由於最近在搞智慧家居類應用,所以可想而知有很多東西需要自定義如遙控器,調節器,還有一些帶動畫效果的View,畢竟叫智慧產品嘛,不能就是開和關兩個選項加一些圖片吧,所以還是要自定義一些控制元件的,今天這個是一個環形調節期,可以適應於空調或者熱水器的遠端調節控制元件,我們主要是用於裝置的調檔。

main.jpg

上次的寫的一個控制元件 炫酷的空氣淨化器控制元件 : AirPurgeLayoutView

1.主要功能

  • 背光燈漸變
  • 背光燈調色
  • 控制環的顏色
  • 控制環形的度數
  • 平滑實現調節
  • 裡面所以引數都可以微調

2.背光燈效果

這裡說的背光燈效果是第二個圓環的陰影背景這裡實現還是非常簡單的,但需要主要一下記得關閉硬體加速,要不然就沒有效果了。

  1. setLayerType(LAYER_TYPE_SOFTWARE, null); //要關閉硬體加速
  2. mPaint.setShadowLayer(mCurShadowRadius, 0, 0, mSecondCircleShadowColor); //設定圓環陰影
  3. 實現動畫效果

sweep.gif

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.實現外圓環環形漸變

這個實現也挺簡單的如果你知道android自定義view有三種常用漸變方法這個一看就知道(1. LinearGradient 線性漸變 2.RadialGradient 輻射漸變 3.SweepGradient 環形漸變)其實還有一些但這三個比較常用不知道的google一下或者看下官網就ok了,這裡用到的是SweepGradient 但有一個問題就是他是360°的顏色從0度開始到最後不能調節顏色開始角度,所以使用時最好在首位加多加一位顏色。

//繪製顏色
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. 滑動控制

實現滑動控制主要是監聽下view的onTouchEvent方法,這裡主要控制元件的邏輯大致是,當使用者手指按下這個控制元件時會判斷是否單機控制元件的第三個控制圓環,如果有出發控制,如果沒有不處理觸控。

slide.gif


    @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;
    }

複製程式碼

5.實現程式碼滑動

這個也很簡單主要是現實根據進度實現動畫性的改變進度,但需要注意的是當觸控時立刻停止動畫,如果動畫在執行的。

control.gif

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.感想

最近開發智慧家居產品,需要時不時定義一些view,但如果你完整的看完過android view的api時,你會發現其實真的不難,很多google都給你封裝好了,像什麼漸變啊,貝塞爾曲線,圖片剪下,動畫,觸控滑動,佈局填充等,你只要學會拼接就可以,所以如果專案需要大量使用自定義控制元件的可以去系統的看一遍view的api。

7. RegulatorView的原始碼地址

8. 空氣淨化器控制元件 : AirPurgeLayoutView

相關文章