2012-07-01 33 views
7

给定任何形状(实心圆,星形,三角形,带有透明区域的位图等)我想知道是否有可能(使用最新的Android API)知道用户是否点击过在视图上,或在它之外。真正的自定义形状的按钮

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

可能吗?

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

回答

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

的情况下的ImageView已设置其宽度&高度WRAP_CONTENT,它真正得到它所需要的尺寸,只有这样,你可以使用Adnan Zahid solution,这可能是这样写:

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

我也想做这样的事情,我最终调整了FrameLayout。 FrameLayout允许您在彼此顶部添加多个视图。

添加一个FrameLayout。在里面你可以添加一个'View',并将其高度和宽度设置为match_parent。在视图之上,添加你想要的按钮。

然后在您的代码中,获取视图的引用并在其上设置onClickListener,以便每当用户触摸该视图时,您都可以处理该事件。在其他按钮上也设置点击监听器。

现在只需处理您的触摸事件。您现在将知道用户是否点击了该按钮或在该按钮之外(用户点击了该视图)。

如果您想创建透明或半透明按钮,请检查https://stackoverflow.com/a/11689915/1117338。 我希望这可以帮助。

1
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    FrameLayout root = (FrameLayout)findViewById(R.id.root); 
    root.setOnTouchListener(new OnTouchListener() {   
     public boolean onTouch(View v, MotionEvent event) { 
      if (v.getId() == ID){ 
       // Your code 
      } 
      return true; 
     } 
    }); 
} 
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; 
} 

这样你就可以得到感动像素的Alpha值。现在您可以轻松检查所触摸的像素是否透明。

+0

这实际上看起来很有前途!不过,我需要先检查一下,然后再选择你的答案。可能会有问题:不同设备屏幕上会发生什么(不同的密度/分辨率)?它会继续工作吗?此外,这种方法是否使用更多的内存这种方式的位图? –

+0

也,即使我不使用位图显示在视图中它会工作吗? –

+0

如果你正在设计不同的屏幕,你必须使用碎片。至于位图,我认为使用普通按钮图像不会使用太多的内存,因为它可以轻松缩放而不会损失太多细节。最后,是的,你可以使用drawbitmap方法,但这需要一个画布,所以我建议使用imageview来代替。 –