自定义形状按钮
Custom shape button
我正在尝试将馅饼的每一片都做成一个按钮。馅饼是图像视图中的一堆矢量可绘制对象。我不一定需要单击实际的饼图切片。我正在考虑使用 Path 绘制透明形状并将其放在顶部并将其设为按钮,但据我了解,可绘制对象不可点击。
我读过一篇博客 post,它显然使用路径来制作自定义形状的图像视图,而且我知道图像视图是可点击的,但在博客 post 中的实现似乎图像视图仍然是矩形的,但是博主在示例中使用的位图只是在图像视图中被修剪为自定义形状。我指的是 post:http://www.androidhub4you.com/2014/10/android-custom-shape-imageview-rounded.html
请像一个五岁的孩子一样向我解释这个。我对编程比较陌生。如果不是 Android Studio 的自动一切,我就不会在这里。
谢谢。
您可以只使用drawArc 和drawCircle 绘制一个径向菜单,并使用触摸点与中心点之间的距离和角度来检测当前正在点击的切片。我为你写了一个示例:
public class RadioButtons extends View {
//the number of slice
private int mSlices = 6;
//the angle of each slice
private int degreeStep = 360 / mSlices;
private int quarterDegreeMinus = -90;
private float mOuterRadius;
private float mInnerRadius;
//using radius square to prevent square root calculation
private float outerRadiusSquare;
private float innerRadiusSquare;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mSliceOval = new RectF();
private static final double quarterCircle = Math.PI / 2;
private float innerRadiusRatio = 0.3F;
//color for your slice
private int[] colors = new int[]{Color.GREEN, Color.GRAY, Color.BLUE, Color.CYAN, Color.DKGRAY, Color.RED};
private int mCenterX;
private int mCenterY;
private OnSliceClickListener mOnSliceClickListener;
private int mTouchSlop;
private boolean mPressed;
private float mLatestDownX;
private float mLatestDownY;
public interface OnSliceClickListener{
void onSlickClick(int slicePosition);
}
public RadioButtons(Context context){
this(context, null);
}
public RadioButtons(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public RadioButtons(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mTouchSlop = viewConfiguration.getScaledTouchSlop();
mPaint.setStrokeWidth(10);
}
public void setOnSliceClickListener(OnSliceClickListener onSliceClickListener){
mOnSliceClickListener = onSliceClickListener;
}
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh){
mCenterX = w / 2;
mCenterY = h / 2;
mOuterRadius = mCenterX > mCenterY ? mCenterY : mCenterX;
mInnerRadius = mOuterRadius * innerRadiusRatio;
outerRadiusSquare = mOuterRadius * mOuterRadius;
innerRadiusSquare = mInnerRadius * mInnerRadius;
mSliceOval.left = mCenterX - mOuterRadius;
mSliceOval.right = mCenterX + mOuterRadius;
mSliceOval.top = mCenterY - mOuterRadius;
mSliceOval.bottom = mCenterY + mOuterRadius;
}
@Override
public boolean onTouchEvent(MotionEvent event){
float currX = event.getX();
float currY = event.getY();
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
mLatestDownX = currX;
mLatestDownY = currY;
mPressed = true;
break;
case MotionEvent.ACTION_MOVE:
if(Math.abs(currX - mLatestDownX) > mTouchSlop || Math.abs(currY - mLatestDownY) > mTouchSlop) mPressed = false;
break;
case MotionEvent.ACTION_UP:
if(mPressed){
int dx = (int) currX - mCenterX;
int dy = (int) currY - mCenterY;
int distanceSquare = dx * dx + dy * dy;
//if the distance between touchpoint and centerpoint is smaller than outerRadius and longer than innerRadius, then we're in the clickable area
if(distanceSquare > innerRadiusSquare && distanceSquare < outerRadiusSquare){
//get the angle to detect which slice is currently being click
double angle = Math.atan2(dy, dx);
if(angle >= -quarterCircle && angle < 0){
angle += quarterCircle;
}else if(angle >= -Math.PI && angle < -quarterCircle){
angle += Math.PI + Math.PI + quarterCircle;
}else if(angle >= 0 && angle < Math.PI){
angle += quarterCircle;
}
double rawSliceIndex = angle / (Math.PI * 2) * mSlices;
if(mOnSliceClickListener != null){
mOnSliceClickListener.onSlickClick((int) rawSliceIndex);
}
}
}
break;
}
return true;
}
@Override
public void onDraw(Canvas canvas){
int startAngle = quarterDegreeMinus;
//draw slice
for(int i = 0; i < mSlices; i++){
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(colors[i % colors.length]);
canvas.drawArc(mSliceOval, startAngle, degreeStep, true, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
canvas.drawArc(mSliceOval, startAngle, degreeStep, true, mPaint);
startAngle += degreeStep;
}
//draw center circle
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mCenterX, mCenterY, mInnerRadius, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mCenterX, mCenterY, mInnerRadius, mPaint);
}
}
我正在尝试将馅饼的每一片都做成一个按钮。馅饼是图像视图中的一堆矢量可绘制对象。我不一定需要单击实际的饼图切片。我正在考虑使用 Path 绘制透明形状并将其放在顶部并将其设为按钮,但据我了解,可绘制对象不可点击。
我读过一篇博客 post,它显然使用路径来制作自定义形状的图像视图,而且我知道图像视图是可点击的,但在博客 post 中的实现似乎图像视图仍然是矩形的,但是博主在示例中使用的位图只是在图像视图中被修剪为自定义形状。我指的是 post:http://www.androidhub4you.com/2014/10/android-custom-shape-imageview-rounded.html
请像一个五岁的孩子一样向我解释这个。我对编程比较陌生。如果不是 Android Studio 的自动一切,我就不会在这里。
谢谢。
您可以只使用drawArc 和drawCircle 绘制一个径向菜单,并使用触摸点与中心点之间的距离和角度来检测当前正在点击的切片。我为你写了一个示例:
public class RadioButtons extends View {
//the number of slice
private int mSlices = 6;
//the angle of each slice
private int degreeStep = 360 / mSlices;
private int quarterDegreeMinus = -90;
private float mOuterRadius;
private float mInnerRadius;
//using radius square to prevent square root calculation
private float outerRadiusSquare;
private float innerRadiusSquare;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mSliceOval = new RectF();
private static final double quarterCircle = Math.PI / 2;
private float innerRadiusRatio = 0.3F;
//color for your slice
private int[] colors = new int[]{Color.GREEN, Color.GRAY, Color.BLUE, Color.CYAN, Color.DKGRAY, Color.RED};
private int mCenterX;
private int mCenterY;
private OnSliceClickListener mOnSliceClickListener;
private int mTouchSlop;
private boolean mPressed;
private float mLatestDownX;
private float mLatestDownY;
public interface OnSliceClickListener{
void onSlickClick(int slicePosition);
}
public RadioButtons(Context context){
this(context, null);
}
public RadioButtons(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public RadioButtons(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mTouchSlop = viewConfiguration.getScaledTouchSlop();
mPaint.setStrokeWidth(10);
}
public void setOnSliceClickListener(OnSliceClickListener onSliceClickListener){
mOnSliceClickListener = onSliceClickListener;
}
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh){
mCenterX = w / 2;
mCenterY = h / 2;
mOuterRadius = mCenterX > mCenterY ? mCenterY : mCenterX;
mInnerRadius = mOuterRadius * innerRadiusRatio;
outerRadiusSquare = mOuterRadius * mOuterRadius;
innerRadiusSquare = mInnerRadius * mInnerRadius;
mSliceOval.left = mCenterX - mOuterRadius;
mSliceOval.right = mCenterX + mOuterRadius;
mSliceOval.top = mCenterY - mOuterRadius;
mSliceOval.bottom = mCenterY + mOuterRadius;
}
@Override
public boolean onTouchEvent(MotionEvent event){
float currX = event.getX();
float currY = event.getY();
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
mLatestDownX = currX;
mLatestDownY = currY;
mPressed = true;
break;
case MotionEvent.ACTION_MOVE:
if(Math.abs(currX - mLatestDownX) > mTouchSlop || Math.abs(currY - mLatestDownY) > mTouchSlop) mPressed = false;
break;
case MotionEvent.ACTION_UP:
if(mPressed){
int dx = (int) currX - mCenterX;
int dy = (int) currY - mCenterY;
int distanceSquare = dx * dx + dy * dy;
//if the distance between touchpoint and centerpoint is smaller than outerRadius and longer than innerRadius, then we're in the clickable area
if(distanceSquare > innerRadiusSquare && distanceSquare < outerRadiusSquare){
//get the angle to detect which slice is currently being click
double angle = Math.atan2(dy, dx);
if(angle >= -quarterCircle && angle < 0){
angle += quarterCircle;
}else if(angle >= -Math.PI && angle < -quarterCircle){
angle += Math.PI + Math.PI + quarterCircle;
}else if(angle >= 0 && angle < Math.PI){
angle += quarterCircle;
}
double rawSliceIndex = angle / (Math.PI * 2) * mSlices;
if(mOnSliceClickListener != null){
mOnSliceClickListener.onSlickClick((int) rawSliceIndex);
}
}
}
break;
}
return true;
}
@Override
public void onDraw(Canvas canvas){
int startAngle = quarterDegreeMinus;
//draw slice
for(int i = 0; i < mSlices; i++){
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(colors[i % colors.length]);
canvas.drawArc(mSliceOval, startAngle, degreeStep, true, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
canvas.drawArc(mSliceOval, startAngle, degreeStep, true, mPaint);
startAngle += degreeStep;
}
//draw center circle
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mCenterX, mCenterY, mInnerRadius, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mCenterX, mCenterY, mInnerRadius, mPaint);
}
}