I don't think there is a way to actually make a clickable area other than rectangular.
You should make your floating button have a width and height set to wrap_content if your circle is an image. Any way you should set it's width and height to match the diameter of the circle. And process the event like this:
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
float radius = layoutParams.width / 2f;
float x = event.getX() - radius;
float y = event.getY() - radius;
if (isInCircle(radius, x, y)) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// perform your action
}
return true;
} else {
return false;
}
}
private boolean isInCircle(float radius, float x, float y) {
if (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) < radius) {
//touch was performed inside the circle;
return true;
} else {
//touched ouside the circle
return false;
}
}
}
);
This will work on any device, as long as your button is tightly wrapped around your drawn circle.
If you don't need the touch event falling deeper, under your floating button when you miss the circle, you can avoid some redundant calculations like this:
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
float radius = layoutParams.width / 2f;
float x = event.getX() - radius;
float y = event.getY() - radius;
if (isInCircle(radius, x, y)) {
// perform your action
}
}
return true;
}
private boolean isInCircle(float radius, float x, float y) {
if (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) < radius) {
//touch was performed inside the circle;
return true;
} else {
//touched ouside the circle
return false;
}
}
}
);
Keep in mind that for this to work your button should be strictly rectangular. if you want a button to be an ellipse the math should be different.