2012-07-01 10 views
7

Dada cualquier forma (ya sea círculo relleno, estrella, triángulo, mapa de bits con áreas transparentes, etc.) Me gustaría saber si es posible (utilizando la última API de Android) saber si el usuario ha hecho clic en la vista, o fuera de ella.Forma del botón real personalizada

Por ejemplo, si tengo un botón circular, me gustaría saber si el usuario ha hecho clic dentro del círculo, pero no fuera de él.

¿Es posible?

Si no, tal vez podría sondear el píxel del evento táctil, y si es transparente, ignórelo, y si no lo está, trátelo como un evento de clic.

Respuesta

1

bien, he encontrado una solución de trabajo para cualquier tipo de vista.

algunas notas:

  • tristemente que utiliza un mapa de bits del tamaño de la vista, pero sólo para una pequeña cantidad de tiempo.

    después de eso, se mantiene donde se considera en el área visible y donde se considera fuera del área visible.

  • podría hacerlo más compatible con la memoria haciendo una matriz de enteros, que tienen banderas. actualmente es una matriz booleana simple.

  • i podía comprobar valores alfa del mapa de bits en JNI en su lugar, y evitar tener el tiempo (corto) donde i tener tanto el mapa de bits y la matriz juntos.

  • si alguien puede ayudar a mejorarlo, podría ser realmente genial.

aquí está el código:

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

en caso de que el imageView ha puesto su anchura & altura para wrap_content, y realmente tiene el tamaño que necesita, sólo entonces se puede utilizar Adnan Zahid solution, que podría ser escrito de esta manera:

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

También quería hacer algo así y terminé retocando con FrameLayout. FrameLayout le permite agregar múltiples vistas una encima de la otra.

Agregue un FrameLayout. Dentro de eso puedes agregar una 'Vista' y establecer su altura y ancho para match_parent. En la parte superior de la Vista, agrega los botones que quieras.

Luego, en su código, obtenga la referencia de la Vista y configure onClickListener en ella para que cada vez que el usuario toque esa Vista, pueda manejar ese evento. Establecer oyentes clic en otros botones también.

Ahora solo maneje sus eventos táctiles. Ahora sabrá si el usuario ha hecho clic en el botón o afuera (el usuario ha hecho clic en la Vista).

Si desea crear botones transparentes o translúcidos, marque https://stackoverflow.com/a/11689915/1117338. Espero que esto ayude.

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

De esta manera se puede obtener el valor alfa del píxel tocado. Ahora puede verificar fácilmente si el píxel tocado es transparente o no.

+0

esto en realidad parece prometedor! Sin embargo, tendré que verificarlo antes de marcar tu respuesta. podría haber un problema: ¿qué pasaría en diferentes pantallas de dispositivos (diferentes densidades/resoluciones)? ¿Seguirá funcionando? también, ¿este método usa más memoria de esta manera para el mapa de bits? –

+0

también, ¿funcionará incluso si no uso un mapa de bits para mostrar en la vista? –

+0

Si está diseñando para pantallas diferentes, debe utilizar fragmentos de todos modos. Y en cuanto al mapa de bits, creo que usar una imagen de botón normal no usará mucha memoria ya que se puede escalar fácilmente sin perder muchos detalles. Por último, sí, puedes usar el método drawbitmap, pero eso requeriría un lienzo, así que te recomendaría usar una vista de imagen en su lugar. –

Cuestiones relacionadas