按钮的真实自定形状自定、形状、按钮、真实

2023-09-04 13:32:52 作者:轉角↘吥洅噯

由于任何形状(无论是实心圆,星星,三角形,位图与透明区域等),我想知道这是否是可能的(采用了最新的Andr​​oid API)知道,如果用户点击视图,或它的外面。

Given any shape (either filled circle, star, triangle, bitmap with transparent areas, etc.) I would like to know if it's possible (using the latest Android API) to know if the user has clicked on the view, or outside of it.

例如,如果我有一个圆形的按钮,我想知道,如果用户点击圆圈内,而不是外在的了。

For example, if I have a circular button, I would like to know if the user has clicked inside the circle, but not outside of it.

这可能吗?

如果没有,也许我可以轮询触摸事件的像素,如果它是透明的,忽略它,如果它不是,处理它作为一个click事件?

If not, maybe I could poll the pixel of the touch event, and if it's transparent, ignore it, and if it isn't, handle it as a click event?

推荐答案

好了,我已经找到了为任何类型的视图是一个有效方法。

ok, i've found a working solution for any type of view.

一些注意事项:

可悲它使用视图的大小的位图,但仅用于时间微量

sadly it uses a bitmap of the size of the view, but only for a tiny amount of time.

之后,它保存在那里它被认为在可视区域和在那里它被认为可见区域之外。

after that, it holds where it's considered on the visible area and where it's considered outside of the visible area.

我可以使通过整数,其中有标志的数组它更多的内存友好。目前,它是一个简单的布尔数组。

i could make it more memory friendly by making an array of integers, which have flags. currently it's a simple boolean array.

我可以在JNI检查位图的Alpha值,而是和避免的(短)的时间在那里我有两个位图和排列在一起。

i could check the bitmap's alpha values in JNI instead, and avoid having the (short) time where i have both the bitmap and the array together.

如果有人可以帮助做的更好,也可能是真正伟大的。

if anyone could help making it better, it could be really great.

这里的code:

public class MainActivity extends Activity
  {
  boolean[] _inVisibleAreaMap;
  private int _width,_height;

  @Override
  protected void onCreate(final Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final View view=findViewById(R.id.imageView1);
    view.setDrawingCacheEnabled(true);
    runJustBeforeBeingDrawn(view,new Runnable()
      {
        @Override
        public void run()
          {
          final Bitmap bitmap=view.getDrawingCache();
          _width=bitmap.getWidth();
          _height=bitmap.getHeight();
          _inVisibleAreaMap=new boolean[_width*_height];
          for(int y=0;y<_width;++y)
            for(int x=0;x<_height;++x)
              _inVisibleAreaMap[y*_width+x]=Color.alpha(bitmap.getPixel(x,y))!=0;
          view.setDrawingCacheEnabled(false);
          bitmap.recycle();
          }
      });
    view.setOnTouchListener(new OnTouchListener()
      {
        @Override
        public boolean onTouch(final View v,final MotionEvent event)
          {
          final int x=(int)event.getX(),y=(int)event.getY();
          boolean isIn=x>=0&&y>=0&&x<_width&&y<_height;
          // if inside bounding box , check if in the visibile area
          if(isIn)
            isIn=_inVisibleAreaMap[y*_width+x];
          if(isIn)
            Log.d("DEBUG","in");
          else Log.d("DEBUG","out");
          return true;
          }
      });
    }

  private static void runJustBeforeBeingDrawn(final View view,final Runnable runnable)
    {
    final ViewTreeObserver vto=view.getViewTreeObserver();
    final OnPreDrawListener preDrawListener=new OnPreDrawListener()
      {
        @Override
        public boolean onPreDraw()
          {
          runnable.run();
          final ViewTreeObserver vto=view.getViewTreeObserver();
          vto.removeOnPreDrawListener(this);
          return true;
          }
      };
    vto.addOnPreDrawListener(preDrawListener);
    }
  }

在情况下的ImageView已设置其宽度和放大器;高度WRAP_CONTENT,它真的有需要,才可以使用大小阿德南·扎希德解决方案,这可能是这样写的:

in case the imageView has set its width&height to wrap_content, and it really got the size it needs, only then you can use Adnan Zahid solution, which could be written this way:

public class MainActivity extends Activity
  {
  private int _width,_height;

  @Override
  protected void onCreate(final Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final ImageView image=(ImageView)findViewById(R.id.imageView1);
    final Bitmap bitmap=((BitmapDrawable)image.getDrawable()).getBitmap();
    _width=bitmap.getWidth();
    _height=bitmap.getHeight();
    image.setOnTouchListener(new OnTouchListener()
      {
        @Override
        public boolean onTouch(final View v,final MotionEvent event)
          {
          final int x=(int)event.getX(),y=(int)event.getY();
          boolean isIn=x>=0&&y>=0&&x<_width&&y<_height;
          if(isIn)
            {
            final int pixel=bitmap.getPixel((int)event.getX(),(int)event.getY());
            final int alphaValue=Color.alpha(pixel);
            isIn=alphaValue!=0;
            }
          if(isIn)
            Log.d("DEBUG","in");
          else Log.d("DEBUG","out");
          return true;
          }
      });
    }
  }