文章目录
前言
提示:这是一个支持四个按钮的的虚拟按盘,并且可自由设置背景图片。
提示:以下是本篇文章正文内容,下面案例可供参考
一、自定义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方法中有操作事件的话,点击时加个判断就好)
总结
此篇文章仅作为自己学习后的心得,用来记录。各位大神如发现问题请指教。