Android 创建圆形的ImageView,因此单击将仅在圆形区域上工作

Android 创建圆形的ImageView,因此单击将仅在圆形区域上工作,android,android-layout,android-view,Android,Android Layout,Android View,嗨,我正在创建一个应用程序 比如说 它不应在圆外响应,但ImageView是矩形的,因此它正在响应 我相信你能理解这个问题 ImageView是矩形的,但它的图像是圆形的,但我只想检测单击圆形图像…您可以将视图附加到图像视图。在这种情况下,侦听器只有一个名为OnTouchListener#onTouch(视图v,MotionEvent)的方法。事件参数具有允许获取触摸坐标的方法。 当您获得相对于ImageView大小的触摸坐标时,您可以检查以下不等式是否为true:(x-x0)^2+(y-y0

嗨,我正在创建一个应用程序

比如说

它不应在圆外响应,但ImageView是矩形的,因此它正在响应

我相信你能理解这个问题


ImageView是矩形的,但它的图像是圆形的,但我只想检测单击圆形图像…

您可以将
视图附加到
图像视图。在这种情况下,侦听器只有一个名为
OnTouchListener#onTouch(视图v,MotionEvent)
的方法。
事件
参数具有允许获取触摸坐标的方法。

当您获得相对于
ImageView
大小的触摸坐标时,您可以检查以下不等式是否为
true
(x-x0)^2+(y-y0)^2您似乎必须计算用户是否在圆形视图内触摸。这必须通过覆盖定制ImageView类的touch事件来实现,我假设您已经编写了该类

起初我以为画一个圆形区域就足够了,但事实并非如此

伪代码:

public class CustomImageView implements ImageView
{
    private Point centerPoint;
    private float radius;

    @Override
    protected void onDraw(Canvas canvasF) 
    {
        Drawable drawable = getDrawable();
        if(centerPoint == null)
        {
            centerPoint = new Point (getWidth() / 2, getHeight() / 2);
            /* 
             * if radius extends to edges, but if circular code 
             * exists already then we should already know what the 
             * radius is at this point I would assume.
             */
            radius = getWidth() / 2;
        }

        /*
         * remaining draw code for manipulating a circle.
         */
    }

    private boolean isInsideCircle(Point touchedPoint)
    {
         int distance = (int) Math.round(Math.pow(touchedPoint.x - centerPoint.x, 2) + Math.pow(touchedPoint.y - centerPoint.y, 2));

         if(distance < Math.pow(radius, 2))
         {
             return true;
         }
         else
         {
             return false;
         }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        Point touchedPoint = new Point(Math.round(event.getX()),   Math.round(event.getY()));

        if(isInsideCircle(touchedPoint))
        {
            return super.onTouchEvent(event);
        }

        return true;
    }
}
公共类CustomImageView实现ImageView
{
专用点中心点;
私有浮动半径;
@凌驾
受保护的空白onDraw(帆布画布)
{
Drawable Drawable=getDrawable();
如果(中心点==null)
{
中心点=新点(getWidth()/2,getHeight()/2);
/* 
*如果半径延伸到边,但如果圆代码
*已经存在,那么我们应该已经知道
*半径就是我假设的这个点。
*/
半径=getWidth()/2;
}
/*
*用于操作圆的剩余绘图代码。
*/
}
专用布尔值isInsideCircle(点接触点)
{
int距离=(int)Math.round(Math.pow(touchedPoint.x-centerPoint.x,2)+Math.pow(touchedPoint.y-centerPoint.y,2));
if(距离<数学功率(半径,2))
{
返回true;
}
其他的
{
返回false;
}
}
@凌驾
公共布尔onTouchEvent(运动事件)
{
点接触点=新点(Math.round(event.getX()),Math.round(event.getY());
if(isInsideCircle(接触点))
{
返回super.onTouchEvent(事件);
}
返回true;
}
}
现在,我可能会将其添加到ImageView类中,以扩展它,并仅在需要时在图像中提供触摸事件


如果图像一直延伸到边缘,则半径更容易确定。否则,需要做一些额外的工作来计算实际区域的半径。

感谢您的支持,基于您的支持,我已经通过下面的方式完成了,它工作得非常完美

ImageView imgView = (ImageView) findViewById(R.id.imageView1);
        imgView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                //CIRCLE :      (x-a)^2 + (y-b)^2 = r^2 
                float centerX, centerY, touchX, touchY, radius;
                centerX = v.getWidth() / 2;
                centerY = v.getHeight() / 2;
                touchX = event.getX();
                touchY = event.getY();
                radius = centerX;
                System.out.println("centerX = "+centerX+", centerY = "+centerY);
                System.out.println("touchX = "+touchX+", touchY = "+touchY);
                System.out.println("radius = "+radius);
                if (Math.pow(touchX - centerX, 2)
                        + Math.pow(touchY - centerY, 2) < Math.pow(radius, 2)) {
                    System.out.println("Inside Circle");
                    return false;
                } else {
                    System.out.println("Outside Circle");
                    return true;
                }
            }
        });
ImageView imgView=(ImageView)findViewById(R.id.imageView1);
imgView.setOnTouchListener(新视图.OnTouchListener(){
@凌驾
公共布尔onTouch(视图v,运动事件){
//圆:(x-a)^2+(y-b)^2=r^2
浮动中心X、中心Y、接触X、接触Y、半径;
centerX=v.getWidth()/2;
centerY=v.getHeight()/2;
touchX=event.getX();
touchY=event.getY();
半径=中心x;
System.out.println(“centerX=“+centerX+”,centerY=“+centerY”);
System.out.println(“touchX=“+touchX+”,touchY=“+touchY”);
System.out.println(“半径=”+半径);
if(数学功率(touchX-centerX,2)
+数学功率(接触中心,2)<数学功率(半径,2)){
System.out.println(“内圆”);
返回false;
}否则{
System.out.println(“外圆”);
返回true;
}
}
});

根据Siddhpura Amit的回答,我刚刚发现,通过这种方法,触摸不会得到ACTION\u CANCEL事件,因此当您移出“内圆”区域时,视图不会保持不变。 我使用了以下变通方法来解决这个问题:

ImageView imgView = (ImageView) findViewById(R.id.imageView1);
imgView.setOnTouchListener(new View.OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
         //CIRCLE :      (x-a)^2 + (y-b)^2 = r^2 
        float centerX = v.getWidth() / 2;
        float centerY = v.getHeight() / 2;
        float touchX = event.getX();
        float touchY = event.getY();
        float radius = centerX;
        Log.d(TAG, "centerX = "+centerX+", centerY = "+centerY);
        Log.d(TAG, "touchX = "+touchX+", touchY = "+touchY);
        Log.d(TAG, "radius = "+radius);
        if (Math.pow(touchX - centerX, 2) + Math.pow(touchY - centerY, 2) < Math.pow(radius, 2)) {
            Log.d(TAG, "Inside Circle");
        } else {
            Log.d(TAG, "Outside Circle");
            if (event.getAction() != MotionEvent.ACTION_CANCEL) {
                event.setAction(MotionEvent.ACTION_CANCEL);
                v.dispatchTouchEvent(event);
                return true;
            }
        }
        return false;
    }
});
ImageView imgView=(ImageView)findViewById(R.id.imageView1);
imgView.setOnTouchListener(新视图.OnTouchListener(){
@凌驾
公共布尔onTouch(视图v,运动事件){
//圆:(x-a)^2+(y-b)^2=r^2
float centerX=v.getWidth()/2;
浮动中心=v.getHeight()/2;
float touchX=event.getX();
float touchY=event.getY();
浮动半径=中心;
Log.d(标记“centerX=“+centerX+”,centerY=“+centerY”);
Log.d(标签“touchX=“+touchX+”,touchY=“+touchY”);
Log.d(标签“radius=“+radius”);
if(Math.pow(touchX-centerX,2)+Math.pow(touch-centerY,2)
排除图像透明区域的简单解决方案

注意:使用PNG图像

 mImageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                if (view == null) return false;
                Bitmap bmp = Bitmap.createBitmap(view.getDrawingCache());
                if (motionEvent.getX() < bmp.getWidth() && motionEvent.getY() < bmp.getHeight()) {
                    //Get color at point of touch
                    int color = bmp.getPixel((int) motionEvent.getX(), (int) motionEvent.getY());
                    bmp.recycle();
                    if (color == Color.TRANSPARENT) {
                        //do not proceed if color is transparent
                        return false;

                    } else {
                        //proceed if color is not transparent
                        return true;
                    }
                }
            }
            return false;
        }
    });
public void setDrawingCache(View view){
        view.setDrawingCacheEnabled(true);
        view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache(true);
    }
mImageView.setOnTouchListener(新视图.OnTouchListener(){
@凌驾
公共布尔onTouch(视图、运动事件、运动事件){
if(motionEvent.getAction()==motionEvent.ACTION\u向下){
if(view==null)返回false;
位图bmp=Bitmap.createBitmap(view.getDrawingCache()
public boolean onTouchImageTransparent(View view, MotionEvent motionEvent){
    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
        Bitmap bmp = Bitmap.createBitmap(view.getDrawingCache());
        if (motionEvent.getX() < bmp.getWidth() && motionEvent.getY() < bmp.getHeight()) {
            //Get color at point of touch
            int color = bmp.getPixel((int) motionEvent.getX(), (int) motionEvent.getY());
            bmp.recycle();
            if (color == Color.TRANSPARENT) {
                //do not proceed if color is transparent
                Log.d("onTouch","Click on Background PNG");
                return false;

            } else {
                //proceed if color is not transparent
                Log.d("onTouch","Click on Image");
                return true;
            }
        }else{
            Log.d("onTouch","Click on somewhere else");
            return false;
        }
    }else{
        Log.d("onTouch","Click on Background");
    }
    return false;
}
    ImageView mImageView = findViewById(R.id.imageView);
    setDrawingCache(mImageView);
    mImageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if(onTouchImageTransparent(view,motionEvent)){
                //action goes here
            }
            return onTouchImageTransparent(view,motionEvent);
        }
    });
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;
    }
}
View button = findViewById(R.id.my_button);
button.setOnTouchListener(new OvalTouchAreaFilter());