I've made this circular button in Android Studio:
I used a custom backgroud. The problem is that the highlighted yellow area in the image, is clickable. I want to reduce the clickable area to just the red circle.
Is there any way to do such thing?
I've made this circular button in Android Studio:
I used a custom backgroud. The problem is that the highlighted yellow area in the image, is clickable. I want to reduce the clickable area to just the red circle.
Is there any way to do such thing?
You cannot remove that transparent area of your image. Because it's a part of your image.
Any kind of image always have rectangular shape. If the corners of the image are transparent, doesn't mean those pixels at the corner are separated from the image! Those pixels are always occupied by your image and you cannot remove that area.
No library yet created that can apart transparent area of an image from image itself.
There was a previous post regarding to clickable area of image but.. it might not solve this case here.
Instead, you should use OnTouchListener to get the x and y of the touch event, then calculate and compare the distance between the center and the even with the radius in order to determine if this is a value click.
Better later than never...
Yes, you can manually reduce the clickable area to just the red circle if you intercept and filter the touch events, by implementing a View.OnTouchListener or overriding onTouchEvent(). The latter requires you to subclass your button, which is easy enough but maybe not quite as desirable, so here is an example of using View.OnTouchListener
to do the job:
OvalTouchAreaFilter.java:
public class OvalTouchAreaFilter implements View.OnTouchListener {
private boolean mIgnoreCurrentGesture;
public TouchAreaFilter() {
mIgnoreCurrentGesture = false;
}
public boolean isInTouchArea(View view, float x, float y) {
int w = view.getWidth();
int h = view.getHeight();
if(w <= 0 || h <= 0)
return false;
float xhat = 2*x / w - 1;
float yhat = 2*y / h - 1;
return (xhat * xhat + yhat * yhat <= 1);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent event) {
int action = event.getActionMasked();
if(action == MotionEvent.ACTION_DOWN) {
mIgnoreCurrentGesture = !this.isInTouchArea(view, event.getX(), event.getY());
return mIgnoreCurrentGesture;
}
boolean ignoreCurrentGesture = mIgnoreCurrentGesture;
if(action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
mIgnoreCurrentGesture = false;
return ignoreCurrentGesture;
}
}
Inside activity onCreate():
View button = findViewById(R.id.my_button);
button.setOnTouchListener(new OvalTouchAreaFilter());
Note that:
isInTouchArea()
can be arbitrarily implemented to set the clickable area to whatever shape you want, even potentially dependent on complex conditions like the background image of the button, etc.
setOnTouchListener()
is not specific to the Button
class. This solution can be used with any type of view whatsoever.
It is not a good solution to just blindly filter all touch messages based on their X and Y position (e.g. as suggested in answers here), as you thereby break the MotionEvent consistency guarantee. This solution instead filters out complete gestures (sequences of MotionEvent
's starting with ACTION_DOWN
and ending with ACTION_UP
/ACTION_CANCEL
, with possibly many other actions inbetween like ACTION_MOVE
) based on their starting coordinates. This means that the approach doesn't break in multi-touch situations.
Create xml drawable like this:
save it as round_button.xml in drawable folder
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#9F2200"/>
<stroke android:width="2dp" android:color="#fff" />
</shape>
and set it as background of Button in xml like this:`
<Button
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/round_button"
android:gravity="center_vertical|center_horizontal"
android:text="hello"
android:textColor="#fff" />