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。
推薦閱讀:
- Android用Canvas繪制貝塞爾曲線
- Android使用貝塞爾曲線畫心形
- Android自定義View繪制貝塞爾曲線的方法
- android實現貝塞爾曲線之波浪效果
- Android自定義view之太極圖的實現教程