自定义一个支持四个方向的虚拟按键,可自由设置背景图片或渐变色或纯色,可作为控制摄像头的控制按钮。


前言

提示:这是一个支持四个按钮的的虚拟按盘,并且可自由设置背景图片。
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、自定义view

public class FictitiousButton extends View {

    private Bitmap mUpBitmap;
    private Bitmap mBottomBitmap;
    private Bitmap mLeftBitmap;
    private Bitmap mRightBitmap;

    private Bitmap mUpBitmap_last;
    private Bitmap mBottomBitmap_last;
    private Bitmap mLeftBitmap_last;
    private Bitmap mRightBitmap_last;

    private final Paint mPaintLeft = new Paint();
    private final Paint mPaintTop = new Paint();
    private final Paint mPaintRight = new Paint();
    private final Paint mPaintBottom = new Paint();
    private final Paint mPaintCenter = new Paint();
    private final Paint mPaintCircularCenter = new Paint();
    private final Paint mPaintLine = new Paint();
    private int mSplitLineWidth = 2;
    private int mDefaultColor = Color.WHITE;
    private int mClickSolidColor = Color.WHITE;
    private int mDefaultCenterColor;
    private int mClickSolidCenterColor = Color.rgb(170,170,170);
    private int mSplitLineColor = Color.BLACK;
    private int mStopColor = Color.WHITE;

    private int width;
    private int height;

    private int lastClick;

    private int topClickBlank;
    private int leftClickBlank;
    private int rightClickBlank;
    private int bottomClickBlank;

    private boolean isShowShadow;


    public FictitiousButton(Context context) {
        super(context);
        initDraw();
    }

    public FictitiousButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        @SuppressLint("CustomViewStyleable") TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.DirectionButton);
        mSplitLineWidth = typeArray.getDimensionPixelSize(R.styleable.DirectionButton_splitLineWidth, 2);
        mSplitLineColor = typeArray.getColor(R.styleable.DirectionButton_splitLineColor, Color.WHITE);
        mDefaultColor = typeArray.getColor(R.styleable.DirectionButton_normalColor, Color.WHITE);
        mClickSolidColor = typeArray.getColor(R.styleable.DirectionButton_pressColor, 0);
        isShowShadow = typeArray.getBoolean(R.styleable.DirectionButton_isShowShadows, false);
        mDefaultCenterColor = typeArray.getColor(R.styleable.DirectionButton_normalCenterColor, 0);
        mClickSolidCenterColor = typeArray.getColor(R.styleable.DirectionButton_pressCenterColor, Color.rgb(170,170,170));

        int mUpImgId = typeArray.getResourceId(R.styleable.DirectionButton_upImage, R.mipmap.home_nvr_up);
        mUpBitmap = BitmapFactory.decodeResource(getResources(), mUpImgId);

        int mBottomImgId = typeArray.getResourceId(R.styleable.DirectionButton_dowmImage, R.mipmap.home_nvr_bottom);
        mBottomBitmap = BitmapFactory.decodeResource(getResources(), mBottomImgId);

        int mLeftImgId = typeArray.getResourceId(R.styleable.DirectionButton_leftImage, R.mipmap.home_nvr_left);
        mLeftBitmap = BitmapFactory.decodeResource(getResources(), mLeftImgId);

        int mRightImgId = typeArray.getResourceId(R.styleable.DirectionButton_rightImage, R.mipmap.home_nvr_right);
        mRightBitmap = BitmapFactory.decodeResource(getResources(), mRightImgId);

        typeArray.recycle();
        initDraw();
    }

    public FictitiousButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initDraw();
    }

    private void initDraw() {
        mPaintLeft.setColor(mDefaultColor);
        mPaintLeft.setStrokeWidth((float) 1.5);
        mPaintLeft.setAntiAlias(true);
        mPaintLeft.setFilterBitmap(true);

        mPaintTop.setColor(mDefaultColor);
        mPaintTop.setStrokeWidth((float) 1.5);
        mPaintTop.setAntiAlias(true);
        mPaintTop.setFilterBitmap(true);

        mPaintRight.setColor(mDefaultColor);
        mPaintRight.setStrokeWidth((float) 1.5);
        mPaintRight.setAntiAlias(true);
        mPaintRight.setFilterBitmap(true);

        mPaintBottom.setColor(mDefaultColor);
        mPaintBottom.setStrokeWidth((float) 1.5);
        mPaintBottom.setAntiAlias(true);
        mPaintBottom.setFilterBitmap(true);

        mPaintLine.setColor(mSplitLineColor);
        mPaintLine.setStrokeWidth((float) 1.5);
        mPaintLine.setAntiAlias(true);
        mPaintLine.setFilterBitmap(true);

        mPaintCircularCenter.setColor(Color.WHITE);
        mPaintCircularCenter.setStrokeWidth((float) 1.5);
        mPaintCircularCenter.setAntiAlias(true);
        mPaintCircularCenter.setFilterBitmap(true);

        mPaintCenter.setColor(Color.rgb(226,227,229));
        mPaintCenter.setStyle(Paint.Style.STROKE);
        mPaintCenter.setStrokeWidth((float) 5.5);
        mPaintCenter.setAntiAlias(true);
        mPaintCenter.setFilterBitmap(true);

        if (isShowShadow) {
            setLayerType(LAYER_TYPE_SOFTWARE, mPaintBottom);
            mPaintBottom.setShadowLayer(2, 0, 1, Color.WHITE);
            setLayerType(LAYER_TYPE_SOFTWARE, mPaintRight);
            mPaintRight.setShadowLayer(2, 1, 0, Color.WHITE);
            setLayerType(LAYER_TYPE_SOFTWARE, mPaintLeft);
            mPaintLeft.setShadowLayer(2, -1, 0, Color.WHITE);
            setLayerType(LAYER_TYPE_SOFTWARE, mPaintTop);
            mPaintTop.setShadowLayer(2, 0, -1, Color.WHITE);
            setLayerType(LAYER_TYPE_SOFTWARE, mPaintCenter);
            mPaintCenter.setShadowLayer(1, 0, 0, Color.WHITE);
        }

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        boolean isFirst = false;
        if (width == 0) {
            isFirst = true;
        }

        int padLeft = getPaddingLeft();
        int padTop = getPaddingTop();
        int padBottom = getPaddingBottom();
        int padRight = getPaddingRight();

        height = getHeight();
        width = getWidth();
        width = width - padLeft - padRight;
        height = height - padTop - padBottom;

        if (isFirst) {
            for (int i = 1; i < 5; i++) {
                resetPaint(i, mDefaultColor, mDefaultCenterColor, 0);
            }
        }

        @SuppressLint("DrawAllocation") RectF rectFbottom = new RectF(padLeft + mSplitLineWidth + bottomClickBlank,
                padTop + mSplitLineWidth * 2 + bottomClickBlank,
                width + padLeft - mSplitLineWidth - bottomClickBlank,
                height + padTop + bottomClickBlank);

        @SuppressLint("DrawAllocation") RectF rectFleft = new RectF(padLeft - leftClickBlank,
                mSplitLineWidth + padTop + leftClickBlank,
                width + padLeft - mSplitLineWidth * 2 - leftClickBlank,
                height + padTop - mSplitLineWidth - leftClickBlank);

        @SuppressLint("DrawAllocation") RectF rectFTop = new RectF(padLeft + mSplitLineWidth + topClickBlank,
                padTop - topClickBlank,
                width + padLeft - mSplitLineWidth - topClickBlank,
                height + padTop - mSplitLineWidth * 2 - topClickBlank);

        @SuppressLint("DrawAllocation") RectF rectFright = new RectF(padLeft + mSplitLineWidth * 2 + rightClickBlank,
                padTop + mSplitLineWidth + rightClickBlank,
                width + padLeft + rightClickBlank,
                height + padTop - mSplitLineWidth - rightClickBlank);

        @SuppressLint("DrawAllocation") RectF rectFCenter = new RectF(
                padLeft ,
                padTop ,
                padRight,
                padBottom);

        @SuppressLint("DrawAllocation") RectF rectFCircularCenter = new RectF(
                padLeft ,
                padTop ,
                padRight,
                padBottom);

        if (width == height)
            canvas.drawCircle(width / 2 + padLeft, height / 2 + padTop, height / 2 - 1, mPaintLine);
        else {
            @SuppressLint("DrawAllocation") RectF rectf = new RectF(padLeft + 1, padTop + 1, width + padLeft - 1, height + padTop - 1);
            canvas.drawOval(rectf, mPaintLine);
        }


        canvas.drawArc(rectFbottom, 45, 90, true, mPaintBottom);
        canvas.drawArc(rectFleft, 135, 90, true, mPaintLeft);
        canvas.drawArc(rectFTop, 225, 90, true, mPaintTop);
        canvas.drawArc(rectFright, 315, 90, true, mPaintRight);
        canvas.drawArc(rectFCircularCenter,-90,90,false, mPaintCircularCenter);
        canvas.drawArc(rectFCenter,-90,90,false, mPaintCenter);

        if (mUpBitmap != null) {

            int topWidth = width - 2 * mSplitLineWidth - 2 * topClickBlank;
            int topHeight = height - mSplitLineWidth * 2;
            @SuppressLint("DrawAllocation") Rect rectTop = new Rect(mSplitLineWidth + padLeft + topClickBlank + topWidth / 3 + topWidth / 10,
                    padTop - topClickBlank + topHeight / 12,
                    width - mSplitLineWidth + padLeft - topClickBlank - topWidth / 3 - topWidth / 10,
                    height - mSplitLineWidth * 2 + padTop - topClickBlank - topHeight / 2 - topHeight / 3);

            canvas.drawBitmap(mUpBitmap, null, rectTop, mPaintTop);

        }
        if (mBottomBitmap != null) {
            int bottomWidth = width - 2 * mSplitLineWidth - 2 * bottomClickBlank;
            int bottomHeight = height - mSplitLineWidth * 2;
            @SuppressLint("DrawAllocation") Rect rectBottom = new Rect(padLeft + mSplitLineWidth + bottomClickBlank + bottomWidth / 3 + bottomWidth / 10,
                    padTop + mSplitLineWidth * 2 + bottomClickBlank + bottomHeight / 2 + bottomHeight / 3,
                    width + padLeft - mSplitLineWidth - bottomClickBlank - bottomWidth / 3 - bottomWidth / 10,
                    height + padTop + bottomClickBlank - bottomHeight / 12);

            canvas.drawBitmap(mBottomBitmap, null, rectBottom, mPaintBottom);
        }
        if (mLeftBitmap != null) {
            int leftWidth = width - mSplitLineWidth * 2;
            int leftHeght = height - 2 * mSplitLineWidth - 2 * leftClickBlank;
            @SuppressLint("DrawAllocation") Rect rectLeft = new Rect(padLeft - leftClickBlank + leftWidth / 12,
                    mSplitLineWidth + padTop + leftClickBlank + leftHeght / 3 + leftHeght / 10,
                    width + padLeft - mSplitLineWidth * 2 - leftClickBlank - leftWidth / 2 - leftWidth / 3,
                    height + padTop - mSplitLineWidth - leftClickBlank - leftHeght / 3 - leftHeght / 10);

            canvas.drawBitmap(mLeftBitmap, null, rectLeft, mPaintBottom);
        }
        if (mRightBitmap != null) {
            int rightWidth = width - mSplitLineWidth * 2;
            int rightHeight = height - 2 * mSplitLineWidth - 2 * rightClickBlank;
            @SuppressLint("DrawAllocation") Rect rectRight = new Rect(padLeft + mSplitLineWidth * 2 + rightClickBlank + rightWidth / 2 + rightWidth / 3,
                    padTop + mSplitLineWidth + rightClickBlank + rightHeight / 3 + rightHeight / 10,
                    width + padLeft + rightClickBlank - rightWidth / 12,
                    height + padTop - mSplitLineWidth - rightClickBlank - rightHeight / 3 - rightHeight / 10);

            canvas.drawBitmap(mRightBitmap, null, rectRight, mPaintBottom);
        }
        canvas.drawCircle(width/2,height/2,width/6 ,mPaintCircularCenter);
        canvas.drawCircle(width/2,height/2,width/6 ,mPaintCenter);
          refreshLastBitmap();
    }

    private void refreshLastBitmap() {
        if (mUpBitmap_last!=mUpBitmap) {
            refreshBitmap(mUpBitmap_last);
            mUpBitmap_last = mUpBitmap;
        }
        if (mBottomBitmap_last!=mBottomBitmap) {
            refreshBitmap(mBottomBitmap_last);
            mBottomBitmap_last = mBottomBitmap;
        }
        if (mLeftBitmap_last!=mLeftBitmap) {
            refreshBitmap(mLeftBitmap_last);
            mLeftBitmap_last = mLeftBitmap;
        }
        if (mRightBitmap_last!=mRightBitmap) {
            refreshBitmap(mRightBitmap_last);
            mRightBitmap_last = mRightBitmap;
        }
    }
    
    private void refreshBitmap(Bitmap bitmap) {
        if (bitmap != null) {
            bitmap.recycle();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        int mDefaultWidth = 300;
        int mDefaultHeight = 300;
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mDefaultWidth, mDefaultHeight);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mDefaultWidth, heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, mDefaultHeight);
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            stopTouchEvent();
        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
            touchEvent(event);
        }

        return true;
    }

    private void touchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        getDirection(x, y);
    }

    private void getDirection(float x, float y) {

        if (width != height && !isTouchOvalIn(x, y))
            return;
        if (width == height) {
            float distanceX = Math.abs((getWidth() >> 1) - x);
            float distanceY = Math.abs((getHeight() >> 1) - y);
            float distanceXY = (float) Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));
            int radius = width >= height ? width / 2 : height / 2;
            if (distanceXY > radius)
                return;
        }
        int radiusX = (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
        int radiusY = (getHeight() - getPaddingTop() - getPaddingBottom()) / 2 + getPaddingTop();

        double angleSource = Math.atan2(y - radiusY, x - radiusX);
        int angle = (int) (angleSource * 180 / Math.PI);
        if (angle <= 0)
            angle = angle + 360;
        int mDefaultLacuna = -2;
        double pointToX = Math.pow((Math.abs(x) - Math.abs(width/2)),2);
        double pointToY = Math.pow((Math.abs(y) - Math.abs(height/2)),2);

        if (Math.sqrt(pointToX + pointToY) > Math.abs(width/6)) {
            if (angle >= 45 && angle < 135) {
                if (lastClick != 1) {
                    if (listener != null)
                        listener.bottomClick();
                    //设置单一颜色,只设置mClickSolidColor就可以了,然后在resetPaint()这个方法中的if下面加
                    // else{
                    //	 **paint.setColor(颜色值);
                    // }
                    //即可
                    resetPaint(1, mClickSolidColor, mClickSolidCenterColor, mDefaultLacuna);
                    lastClick = 1;
                }
            } else if (angle >= 135 && angle < 225) {
                if (lastClick != 2) {
                    if (listener != null)
                        listener.leftClick();
                    resetPaint(2, mClickSolidColor, mClickSolidCenterColor, mDefaultLacuna);
                    lastClick = 2;
                }

            } else if (angle >= 225 && angle < 315) {
                if (lastClick != 3) {
                    if (listener != null)
                        listener.topClick();
                    resetPaint(3, mClickSolidColor, mClickSolidCenterColor, mDefaultLacuna);
                    lastClick = 3;
                }
            } else {
                if (lastClick != 4) {
                    if (listener != null)
                        listener.rightClick();
                    resetPaint(4, mClickSolidColor, mClickSolidCenterColor, mDefaultLacuna);
                    lastClick = 4;
                }

            }
            invalidate();
        }


    }

    private boolean isTouchOvalIn(float x, float y) {
        int centerX = width / 2 + getPaddingLeft();
        int centerY = height / 2 + getPaddingTop();
        boolean isFocusInX = width > height ? true : false;
        int a;
        int b;
        if (isFocusInX) {
            a = width / 2;
            b = height / 2;
        } else {
            a = height / 2;
            b = width / 2;
        }
        double c = Math.sqrt(Math.pow(a, 2) - Math.pow(b, 2));
        double f1;
        double f2;

        if (isFocusInX) {
            double xLeft = centerX - c;
            double xRight = centerX + c;
            f1 = getLengthBy2Dot(x, y, xLeft, centerY);
            f2 = getLengthBy2Dot(x, y, xRight, centerY);
        } else {
            double yUp = centerY - c;
            double yDown = centerY + c;
            f1 = getLengthBy2Dot(x, y, centerX, yUp);
            f2 = getLengthBy2Dot(x, y, centerX, yDown);
        }
        if ((f1 + f2) <= (2 * a))
            return true;
        return false;
    }

    private double getLengthBy2Dot(float srcX, float srcY, double desX, double desY) {
        return Math.sqrt(Math.pow(Math.abs(srcX - desX), 2) + Math.pow(Math.abs(srcY - desY), 2));
    }

    private void resetPaint(int who, int color, int centerColor, int lacuna) {
        switch (who) {
            case 1:
                if (centerColor != 0) {
                    RadialGradient radialGradient = new RadialGradient(width / 2 + getPaddingLeft()
                            , height / 2 + getPaddingTop()
                            , width / 2 - mSplitLineWidth
                            , centerColor, color
                            , RadialGradient.TileMode.CLAMP
                    );
                    mPaintBottom.setShader(radialGradient);
                }
                bottomClickBlank = lacuna;
                break;
            case 2:
                if (centerColor != 0) {
                    RadialGradient radialGradient2 = new RadialGradient(width / 2 + getPaddingLeft()
                            , height / 2 + getPaddingTop()
                            , width / 2 - mSplitLineWidth
                            , centerColor, color
                            , RadialGradient.TileMode.CLAMP
                    );
                    mPaintLeft.setShader(radialGradient2);
                }

                leftClickBlank = lacuna;
                break;
            case 3:
                if (centerColor != 0) {
                    RadialGradient radialGradient3 = new RadialGradient(width / 2 + getPaddingLeft()
                            , height / 2 + getPaddingTop()
                            , width / 2 - mSplitLineWidth
                            , centerColor, color
                            , RadialGradient.TileMode.CLAMP
                    );
                    mPaintTop.setShader(radialGradient3);
                }

                topClickBlank = lacuna;
                break;
            case 4:
                if (centerColor != 0) {
                    RadialGradient radialGradient4 = new RadialGradient(width / 2 + getPaddingLeft()
                            , height / 2 + getPaddingTop()
                            , width / 2 - mSplitLineWidth
                            , centerColor, color
                            , RadialGradient.TileMode.CLAMP
                    );
                    mPaintRight.setShader(radialGradient4);
                }
                rightClickBlank = lacuna;
                break;
        }

    }

    private void stopTouchEvent() {
        if (listener != null) {
            listener.stopTouch();
        }
        resetPaint(lastClick, mClickSolidColor, mStopColor, 0);
        invalidate();
        lastClick = 0;
    }

    public interface OnItemClickListener {
        void topClick();

        void bottomClick();

        void leftClick();

        void rightClick();

        void stopTouch();
    }

    private OnItemClickListener listener;

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }

}

二、使用步骤

1.在XML中使用方法

<com.*.*.*.View.FictitiousButton
            android:layout_width="@dimen/com_160dp"
            android:layout_height="@dimen/com_160dp"/>

//宽和高可随意设置

2.在activity中使用

FictitiousButton mFictitiousButton = findViewById(R.id.fict_btn);
        mFictitiousButton.setOnItemClickListener(new FictitiousButton.OnItemClickListener() {
            @Override
            public void topClick() {
                
            }

            @Override
            public void bottomClick() {

            }

            @Override
            public void leftClick() {

            }

            @Override
            public void rightClick() {

            }

            @Override
            public void stopTouch() {

            }
        });

3. 该View中的stopTouch() 再点击中间的圆形手势离开后也会执行,只要不在stopTouch里面些什么操作就不会影响(一旦在stopTouch方法中有操作事件的话,点击时加个判断就好)


总结

此篇文章仅作为自己学习后的心得,用来记录。各位大神如发现问题请指教。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值