Android自定義View實現遙控器按鈕

本文實例為大傢分享瞭Android自定義View實現遙控器按鈕的具體代碼,供大傢參考,具體內容如下

效果圖:

原理:

  • 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);
 }

源碼:

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

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: