您好我正在创建tabla App,
例如
它不应该在圆形外响应,但ImageView是矩形,所以它正在响应
我相信你能理解这个问题
ImageView是矩形,但它的图像是圆的,但我想检测仅在圆形图像上点击...
答案 0 :(得分:6)
感谢您的支持,基于您通过以下方式提供的支持,并且工作正常
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;
}
}
});
答案 1 :(得分:5)
您似乎必须计算用户是否在圆形视图中触摸。这必须通过覆盖我假设您已编写的自定义ImageView类的触摸事件来实现。
最初我曾想过画一个圆形区域已经足够了,但事实并非如此。
伪代码:
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;
}
}
我现在可能最终将此添加到我的ImageView类中以对其进行扩展,并在我需要时仅在图像中提供触摸事件。
如果图像一直到边缘,则半径更容易确定。否则,需要做一些额外的工作来弄清楚实际区域的半径是什么。
答案 2 :(得分:2)
您可以将View.OnTouchListener
附加到ImageView
。在该侦听器中只有一个名为OnTouchListener#onTouch (View v, MotionEvent event)
的方法。 event
参数具有允许获取触摸坐标的方法
当您获得相对于ImageView
大小的触摸坐标时,您可以检查以下不等式是否为true
:(x - x0) ^ 2 + (y - y0) ^ 2 <= R ^ 2
,其中(x,y)
- ImageView
为中心坐标,(x0, y0)
- 触摸坐标,R
是ImageView
可绘制半径(在您的情况下,它将是ImageView
宽度的一半)。
如果它是true
,您可以进一步传播触摸事件并返回false
,否则返回true
。
答案 3 :(得分:0)
根据Siddhpura Amit的回答,我发现通过这种方法,触摸不会获得ACTION_CANCEL事件,因此当你离开&#34; Inside Circle&#34;时,视图不会被触及。区域。 我使用以下解决方法来解决这个问题:
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;
}
});
答案 4 :(得分:0)
排除图像透明区域的简单解决方案。
注意:使用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;
}
});
答案 5 :(得分:0)
这里是 @Kedar Tendolkar
的很好的解决方案参考基于PNG图片的选择...以非透明颜色检测 onTouch 图片。
因此,如果您的PNG图片具有透明的背景,则可以帮助您根据自身的图像检测触摸活动,如果颜色等于透明,则会检测为背景并且点击将被绕过。
setDrawingCache
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);
}
onTouchImageTransparent
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;
}
然后将onTouch Listener设置为图像视图
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);
}
});
答案 6 :(得分:0)
从我的回答到:https://stackoverflow.com/a/64246201/12235376
如果您通过实现View.OnTouchListener或重写onTouchEvent()来拦截和过滤触摸事件,则可以将可点击区域手动减小到指定的圆形区域。后者要求您对按钮进行子类化,这很容易,但可能并不理想,因此下面是使用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;
}
}
内部活动onCreate():
View button = findViewById(R.id.my_button);
button.setOnTouchListener(new OvalTouchAreaFilter());
请注意:
isInTouchArea()
可以任意实现,以将可点击区域设置为所需的任何形状,甚至可能取决于复杂条件,例如按钮的背景图像等。
setOnTouchListener()
并非特定于Button
类。该解决方案可用于任何类型的视图。
仅根据所有触摸消息的X和Y位置(例如,根据其他答案中的建议)盲目过滤所有触摸消息(或仅ACTION_DOWN
)不是一个好的解决方案,因为{3}}。相反,此解决方案可以过滤出完整手势(MotionEvent
的顺序以ACTION_DOWN
开始,以ACTION_UP
/ ACTION_CANCEL
结尾,可能还有许多其他手势ACTION_MOVE
之间的动作基于其起始坐标。这意味着该方法在多点触摸情况下不会中断。