真正的自定义按钮形状

and*_*per 7 android transparent android-custom-view onclicklistener

给定任何形状(填充圆形,星形,三角形,带透明区域的位图等)我想知道是否可以(使用最新的Android API)知道用户是否已点击视图或其外部.

例如,如果我有一个圆形按钮,我想知道用户是否已在圆圈内部点击,但不在其外部.

可能吗?

如果没有,也许我可以轮询触摸事件的像素,如果它是透明的,忽略它,如果不是,请将其作为点击事件处理?

Adn*_*hid 8

ImageView image=(ImageView) findViewById(R.id.imageView1);
image.setOnTouchListener(this);
Bitmap bitmap = ((BitmapDrawable)image.getDrawable()).getBitmap();    

@Override
public boolean onTouch(View v, MotionEvent event) {
    // TODO Auto-generated method stub
    int pixel = bitmap.getPixel((int)event.getX(), (int)event.getY());
    int alphaValue=Color.alpha(pixel);
    return true;
}
Run Code Online (Sandbox Code Playgroud)

这样您就可以获得所触摸像素的alpha值.现在,您可以轻松检查触摸的像素是否透明.


and*_*per 1

好的,我已经找到了适用于任何类型视图的有效解决方案。

一些注意事项:

  • 遗憾的是,它使用了视图大小的位图,但只使用了很短的时间。

    之后,它保存在可见区域内的位置以及在可见区域之外的位置。

  • 我可以通过创建一个带有标志的整数数组来使其更加内存友好。目前它是一个简单的布尔数组。

  • 我可以在 JNI 中检查位图的 alpha 值,并避免在(短)时间内将位图和数组放在一起。

  • 如果有人可以帮助使它变得更好,那就太好了。

这是代码:

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);
    }
  }
Run Code Online (Sandbox Code Playgroud)

如果imageView已经将其宽度和高度设置为wrap_content,并且它确实得到了它需要的大小,那么你就可以使用Adnan Zahid解决方案,可以这样写:

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;
          }
      });
    }
  }
Run Code Online (Sandbox Code Playgroud)

编辑: runJustBeforeBeingDrawn 的替代方案:/sf/answers/1969521921/