Androidアナログ音量制御設計コンテストのProgressView

8568 ワード

効果図
ScreenGif4.gif
  • は、viewを回転させるか、直接ドラッグすることによって進捗を制御することができる.
  • 回転角度によって音量の移動速度が
  • に変化する.
  • 回転角度によって、帰位時の速度が
  • に変化する.
    実装プロセス
  • は、onMeasure()を書き換え、高さが外部矩形の高さ+paddingとなるようにする.
  • onDraw()を書き換え、2つの長方形と1つのボールを描画します.
  • 書き換えonTouchEvent()は、ボールをクリックして移動するか回転して移動するかを判断し、クリックがコントロールの左半分か右半分かを判断し、指を上げたときにアニメーションに戻る.
  • 音量変更インタフェースを外部で使用するように設定します.

  • 使用
    外層LinearlayoutにclipChildred=falseを追加することを忘れないでください.
    
    
        
        
    
    

    コード#コード#
    public class ProgressView extends View {
        private static final String TAG = "HappyVoiceView";
        /**
         *        
         */
        private Paint outRectPaint;
        /**
         *        
         */
        private Paint innerRectPaint;
        /**
         *        
         */
        private Paint ballPaint;
        /**
         *   ,  ,      
         */
        private RectF rectF1, rectF2, ballRect;
        /**
         *       
         */
        private int outRectHeight = 50;
        /**
         *        
         */
        private int innerRectHeight = 20;
        /**
         *      
         */
        private int circleRadius = 15;
        /**
         *          
         */
        private int length = 0;
        /**
         *        
         */
        private boolean doRoate = false;
        /**
         *       
         */
        private float downY;
        /**
         *   
         */
        private int degress = 0;
        /**
         *       
         */
        private ValueAnimator valueAnimator;
        /**
         *       
         */
        private int ballCurrentLength = 0;
        /**
         *        
         */
        private boolean isTouchLeft = false;
        /**
         *         
         */
        private boolean isTouchBall = false;
        /**
         *         
         */
        private int speed = 1;
        /**
         *       
         */
        private int minSpeed = 2;
        /**
         *       
         */
        private OnVoiceUpdateLinstener voiceUpdateLinstener;
    
        public void setVoiceUpdateLinstener(OnVoiceUpdateLinstener voiceUpdateLinstener) {
            this.voiceUpdateLinstener = voiceUpdateLinstener;
        }
    
        public ProgressView(Context context) {
            super(context);
            init();
        }
        public ProgressView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
        public ProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    
            setMeasuredDimension(widthSize, outRectHeight + getPaddingTop() + getPaddingBottom());
    
        }
        private void init() {
            outRectPaint = initPaint();
            outRectPaint.setColor(Color.CYAN);
            innerRectPaint = initPaint();
            innerRectPaint.setColor(Color.YELLOW);
            ballPaint = initPaint();
            ballPaint.setColor(Color.RED);
            ballRect = new RectF();
        }
        private void initValueAnimator() {
            valueAnimator = ValueAnimator.ofInt(degress, 0);
              valueAnimator.setDuration(Math.abs(degress)/10*100);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    degress = (int) valueAnimator.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.start();
        }
        private Paint initPaint() {
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  //   
            paint.setDither(true);  //   
            paint.setColor(Color.CYAN);
            paint.setStyle(Paint.Style.FILL);
            paint.setStrokeCap(Paint.Cap.SQUARE);
            return paint;
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.translate(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
            dealBallLength();
            rectF1 = new RectF((-getMeasuredWidth() / 2) + getPaddingLeft(), -outRectHeight / 2, (getMeasuredWidth() / 2) - getPaddingLeft(), outRectHeight / 2);
            rectF2 = new RectF((-getMeasuredWidth() / 2) + getPaddingLeft() + getPaddingLeft(), -innerRectHeight / 2, (getMeasuredWidth() / 2) - getPaddingLeft() - getPaddingLeft(), innerRectHeight / 2);
            length = (int) rectF2.width();
            canvas.rotate(degress);
            canvas.drawRoundRect(rectF1, 10, 10, outRectPaint);
            canvas.drawRoundRect(rectF2, 20, 20, innerRectPaint);
            canvas.drawCircle((rectF2.left + ballCurrentLength) + circleRadius / 2, rectF2.centerY(), circleRadius, ballPaint);
            ballRect.left = (rectF2.left + ballCurrentLength) + circleRadius / 2 - circleRadius;
            ballRect.right = (rectF2.left + ballCurrentLength) + circleRadius / 2 + circleRadius;
            ballRect.top = rectF2.centerY() - circleRadius;
            ballRect.bottom = rectF2.centerY() + circleRadius;
    
            if (voiceUpdateLinstener != null) {
                voiceUpdateLinstener.onVoiceChanged((int) ((float) ballCurrentLength / length * 100));
            }
        }
        private int dealBallLength() {
            speed = Math.abs(degress) / 3 + minSpeed;
            if (degress > 0 && ballCurrentLength < length) {
                speed = ballCurrentLength + speed > length ? (length - ballCurrentLength) : speed;
                ballCurrentLength += speed;
                invalidate();
            } else if (degress < 0 && ballCurrentLength > 0) {
                speed = ballCurrentLength - speed < 0 ? ballCurrentLength : speed;
                ballCurrentLength -= speed;
                invalidate();
            }
    
            return ballCurrentLength;
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float y = event.getY();
            float x = event.getX();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (valueAnimator != null && valueAnimator.isRunning()) {
                        return false;
                    }
                    if (ballRect.contains(event.getX() - getMeasuredWidth() / 2, y - getMeasuredHeight() / 2)) {
                        isTouchBall = true;
                        break;
                    }
                    if (rectF1.contains(event.getX() - getMeasuredWidth() / 2, y - getMeasuredHeight() / 2)) {   //      
                        doRoate = true;
                        downY = (int) event.getY();
                        if (event.getX() - getMeasuredWidth() / 2 <= 0) {
                            isTouchLeft = true;
                        } else {
                            isTouchLeft = false;
                        }
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (isTouchBall) {
                        ballCurrentLength = (int) (x - getPaddingLeft() - getPaddingLeft());
                        if (ballCurrentLength < 0) {
                            ballCurrentLength = 0;
                        } else if (ballCurrentLength > length) {
                            ballCurrentLength = length;
                        }
                        invalidate();
                        break;
                    }
                    x = (float) Math.atan((y - downY) / rectF1.right);
                    degress = (int) Math.toDegrees(x);
                    degress = isTouchLeft ? -degress : degress;
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    if (doRoate) {
                        initValueAnimator();
                    }
                    doRoate = false;
                    isTouchBall = false;
                    break;
            }
            return true;
        }
        public interface OnVoiceUpdateLinstener {
            void onVoiceChanged(int voice);
        }
    }