本文实例为大家分享了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);
}
}