Android自定义View实现遥控器按钮

本文实例为大家分享了Android自定义View实现遥控器按钮的具体代码,供大家参考,具体内容如下

效果图:

Android自定义View实现遥控器按钮_第1张图片

原理:

  • onSizeChanged拿到控件宽高,进行path和region的计算(此处,path和region的坐标值都是以viewWidth/2,viewHeight/2为坐标原点进行计算的)
  • 画布平移,绘制5个path
  • 点击事件,判断是否处于相应的region区域内,进行控件的重绘
  • 点击事件motionEvent的原始坐标(getX和getY),是以viewParent的左上角为坐标原点的,需要经过matrix转换成以控件中心点为原点的坐标体系。

Region区域,paint的style设置为stroke模式,遍历绘制

mPaint.setColor(Color.RED);
RegionIterator iterator = new RegionIterator(topRegion);
 Rect r = new Rect();
 while (iterator.next(r)) {
      canvas.drawRect(r, mPaint);
 }

Android自定义View实现遥控器按钮_第2张图片

源码:

public class RemoteControlMenu extends View {

    private int mWidth;
    private int mHeight;

    private RectF bigRectF;
    private int bigRadius;
    private RectF smallRectF;
    private int smallRadius;
    private int padding = 20;
    private int sweepAngel = 80;
    private int offsetAngel;

    @TouchArea
    private int mTouchArea = TouchArea.INVALID;

    private Paint mPaint;
    private Region topRegion, bottomRegion, leftRegion, rightRegion, centerRegion, globalRegion;
    private Path topPath, bottomPath, leftPath, rightPath, centerPath, selectedPath;

    Matrix mMapMatrix;

    private int unselectedColor = 0xff4c5165;
    private int selectedColor = 0xffdd9181;

    private boolean isSelected = false;


    public RemoteControlMenu(Context context) {
        this(context, null);
    }

    public RemoteControlMenu(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RemoteControlMenu(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(4);
        mPaint.setColor(unselectedColor);

        offsetAngel = (360 - sweepAngel * 4) / 4;
        bigRectF = new RectF();
        smallRectF = new RectF();

        topRegion = new Region();
        bottomRegion = new Region();
        leftRegion = new Region();
        rightRegion = new Region();
        centerRegion = new Region();
        globalRegion = new Region();
        topPath = new Path();
        bottomPath = new Path();
        leftPath = new Path();
        rightPath = new Path();
        centerPath = new Path();
        mMapMatrix = new Matrix();
    }

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({TouchArea.LEFT, TouchArea.TOP, TouchArea.RIGHT, TouchArea.BOTTOM,
            TouchArea.CENTER, TouchArea.INVALID})
    private @interface TouchArea {
        int LEFT = 1;
        int TOP = 2;
        int RIGHT = 3;
        int BOTTOM = 4;
        int CENTER = 5;
        int INVALID = 0;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float[] pts = new float[2];
        pts[0] = event.getX();
        pts[1] = event.getY();
        Log.d("zhen", "原始触摸位置:" + Arrays.toString(pts) + " mMapMatrix: " + mMapMatrix);
        mMapMatrix.mapPoints(pts);

        int x = (int) pts[0];
        int y = (int) pts[1];
        Log.w("zhen", "转换后的触摸位置:" + Arrays.toString(pts) + " mMapMatrix: " + mMapMatrix);
        int touchArea = TouchArea.INVALID;
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                if (leftRegion.contains(x, y)) {
                    touchArea = TouchArea.LEFT;
                }
                if (topRegion.contains(x, y)) {
                    touchArea = TouchArea.TOP;
                }
                if (rightRegion.contains(x, y)) {
                    touchArea = TouchArea.RIGHT;
                }
                if (bottomRegion.contains(x, y)) {
                    touchArea = TouchArea.BOTTOM;
                }
                if (centerRegion.contains(x, y)) {
                    touchArea = TouchArea.CENTER;
                }
                if (touchArea == TouchArea.INVALID) {
                    mTouchArea = touchArea;
                    Log.w("zhen", "点击outside");
                } else {
                    if (mTouchArea == touchArea) {
                        //取消选中
                        isSelected = false;
                        mTouchArea = TouchArea.INVALID;
                    } else {
                        //选中
                        isSelected = true;
                        mTouchArea = touchArea;
                    }
                    Log.w("zhen", "按钮状态 mTouchArea " + mTouchArea + " isSelected: " + isSelected);
                    if (mListener != null) {
                        mListener.onMenuClicked(mTouchArea, isSelected);
                    }
                    invalidate();
                }
                break;
        }

        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        //大圆
        bigRadius = (Math.min(mWidth, mHeight) - 250) / 2;
        bigRectF.set(-bigRadius, -bigRadius, bigRadius, bigRadius);
        //小圆
        smallRadius = (bigRadius - padding) / 2;
        smallRectF.set(-smallRadius - padding, -smallRadius - padding,
                smallRadius + padding, smallRadius + padding);

        mMapMatrix.reset();
        globalRegion.set(-mWidth / 2, -mHeight / 2, mWidth / 2, mHeight / 2);

        centerPath.addCircle(0, 0, smallRadius, Path.Direction.CW);
        centerRegion.setPath(centerPath, globalRegion);

        float startAngel = -sweepAngel / 2f;
        rightPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        rightPath.arcTo(smallRectF, startAngel, -sweepAngel);
        rightPath.close();
        rightRegion.setPath(rightPath, globalRegion);

        startAngel += offsetAngel;
        bottomPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        bottomPath.arcTo(smallRectF, startAngel, -sweepAngel);
        bottomPath.close();
        bottomRegion.setPath(bottomPath, globalRegion);

        startAngel += offsetAngel;
        leftPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        leftPath.arcTo(smallRectF, startAngel, -sweepAngel);
        leftPath.close();
        leftRegion.setPath(leftPath, globalRegion);

        startAngel += offsetAngel;
        topPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        topPath.arcTo(smallRectF, startAngel, -sweepAngel);
        topPath.close();
        topRegion.setPath(topPath, globalRegion);
        Log.d("zhen", "globalRegion: " + globalRegion);
        Log.d("zhen", "globalRegion: " + globalRegion);
        Log.d("zhen", "leftRegion: " + leftRegion);
        Log.d("zhen", "topRegion: " + topRegion);
        Log.d("zhen", "rightRegion: " + rightRegion);
        Log.d("zhen", "bottomRegion: " + bottomRegion);
        Log.d("zhen", "centerRegion: " + centerRegion);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth / 2, mHeight / 2);
        // 获取测量矩阵(逆矩阵)
        if (mMapMatrix.isIdentity()) {
            canvas.getMatrix().invert(mMapMatrix);
        }

        mPaint.setColor(unselectedColor);
        canvas.drawPath(centerPath, mPaint);
        canvas.drawPath(rightPath, mPaint);
        canvas.drawPath(bottomPath, mPaint);
        canvas.drawPath(leftPath, mPaint);
        canvas.drawPath(topPath, mPaint);

        if (!isSelected) return;
        mPaint.setColor(selectedColor);
        switch (mTouchArea) {
            case TouchArea.LEFT:
                canvas.drawPath(leftPath, mPaint);
                break;
            case TouchArea.TOP:
                canvas.drawPath(topPath, mPaint);
                break;
            case TouchArea.RIGHT:
                canvas.drawPath(rightPath, mPaint);
                break;
            case TouchArea.BOTTOM:
                canvas.drawPath(bottomPath, mPaint);
                break;
            case TouchArea.CENTER:
                canvas.drawPath(centerPath, mPaint);
                break;
        }
        Log.e("zhen", " touchArea: " + mTouchArea);

        //Android还提供了一个RegionIterator来对Region中的所有矩阵进行迭代,
        // 可以使用该类,获得某个Region的所有矩阵
        //通过遍历region中的矩阵,并绘制出来,来绘制region
//        mPaint.setColor(Color.RED);
//        RegionIterator iterator = new RegionIterator(topRegion);
//        Rect r = new Rect();
//        while (iterator.next(r)) {
//            canvas.drawRect(r, mPaint);
//        }
//
//        mPaint.setColor(Color.BLUE);
//        RegionIterator iterator1 = new RegionIterator(leftRegion);
//        Rect r1 = new Rect();
//        while (iterator1.next(r1)) {
//            canvas.drawRect(r1, mPaint);
//        }
//
//        mPaint.setColor(Color.BLACK);
//        RegionIterator iterator2 = new RegionIterator(rightRegion);
//        Rect r2 = new Rect();
//        while (iterator2.next(r2)) {
//            canvas.drawRect(r2, mPaint);
//        }
//
//        mPaint.setColor(Color.YELLOW);
//        RegionIterator iterator3 = new RegionIterator(bottomRegion);
//        Rect r3 = new Rect();
//        while (iterator3.next(r3)) {
//            canvas.drawRect(r3, mPaint);
//        }
//
//        mPaint.setColor(Color.GREEN);
//        RegionIterator iterator4 = new RegionIterator(centerRegion);
//        Rect r4 = new Rect();
//        while (iterator4.next(r4)) {
//            canvas.drawRect(r4, mPaint);
//        }
    }

    private MenuListener mListener;

    public void setListener(MenuListener listener) {
        mListener = listener;
    }

    // 点击事件监听器
    public interface MenuListener {
        void onMenuClicked(int type, boolean isSelected);
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

你可能感兴趣的:(Android自定义View实现遥控器按钮)