Android 圆形按钮可点击区域

Android circular button clickable area

我在 Android Studio 中制作了这个圆形按钮:

我使用了自定义背景。问题是图像中突出显示的黄色区域是可点击的。我想将可点击区域缩小到只有红色圆圈。

有什么办法可以做到吗?

像这样创建 xml 可绘制对象:

将其另存为 round_button.xml 在 drawable 文件夹中

    <?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>

并将其设置为 xml 中 Button 的背景,如下所示:`

<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" />

不能删除图像的透明区域。因为它是你形象的一部分。

任何类型的图像总是矩形。如果图像的角是透明的,并不意味着角上的那些 像素与图像分离! 这些像素 始终被您的图像占据 并且您无法删除该区域。

尚未创建可以将图像的透明区域与图像本身分开的库。

之前有一个 post 关于 clickable area of image 但是..它可能无法解决这里的问题。

相反,您应该使用OnTouchListener获取触摸事件的x和y,然后计算中心和偶数之间的距离并与半径进行比较以确定这是否是一个值点击。

迟到总比不到好...

,如果拦截和过滤触摸事件,可以通过实现View.OnTouchListener or overriding onTouchEvent()手动将可点击区域缩小到红圈。后者要求您使用 class 按钮,这很简单,但可能不太理想,所以这里有一个使用 View.OnTouchListener 来完成这项工作的示例:

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;
    }
}

内部 activity onCreate():

View button = findViewById(R.id.my_button);
button.setOnTouchListener(new OvalTouchAreaFilter());

注意:

  • isInTouchArea()可以任意实现,将可点击区域设置为您想要的任何形状,甚至可能依赖于按钮的背景图像等复杂条件

  • setOnTouchListener()不特定于Buttonclass。此解决方案可用于任何类型的视图。

  • 根据 X 和 Y 位置盲目过滤所有触摸消息并不是一个好的解决方案(例如,如答案 here), as you thereby break the MotionEvent consistency guarantee 中所建议的那样)。该解决方案反而会过滤掉 完整手势MotionEvent 的序列以 ACTION_DOWN 开始并以 ACTION_UP/ACTION_CANCEL 结束,中间可能有许多其他动作,例如 ACTION_MOVE) 基于它们的起始坐标。这意味着该方法在 multi-touch 情况下不会中断。