7

Data qualsiasi forma (cerchio pieno, stella, triangolo, bitmap con aree trasparenti, ecc.) Vorrei sapere se è possibile (utilizzando l'ultima API di Android) sapere se l'utente ha fatto clic alla vista, o al di fuori di esso.Forma personalizzata reale del pulsante

Ad esempio, se ho un pulsante circolare, vorrei sapere se l'utente ha fatto clic all'interno del cerchio, ma non al di fuori di esso.

È possibile?

In caso contrario, forse potrei eseguire il polling del pixel dell'evento touch e, se è trasparente, ignorarlo e, in caso contrario, gestirlo come evento click?

risposta

1

ok, ho trovato una soluzione funzionante per qualsiasi tipo di visualizzazione.

alcune note:

  • purtroppo utilizza una bitmap delle dimensioni della vista, ma solo per una piccola quantità di tempo.

    successivamente, mantiene dove è considerato nell'area visibile e dove viene considerato al di fuori dell'area visibile.

  • Potrei renderlo più facile da utilizzare per la memoria creando una matrice di numeri interi, che hanno contrassegni. attualmente è un semplice array booleano.

  • potrei controllare i valori alfa della bitmap in JNI invece, ed evitare di avere il (breve) tempo in cui ho sia la bitmap che l'array insieme.

  • se qualcuno potesse contribuire a migliorarlo, potrebbe essere davvero grandioso.

Ecco il codice:

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

nel caso in cui l'ImageView ha fissato la sua larghezza & altezza wrap_content, ed è veramente preso le dimensioni di cui ha bisogno, solo allora è possibile utilizzare Adnan Zahid solution, che potrebbe essere scritto in questo modo:

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

Volevo anche fare qualcosa del genere e ho finito col tweaking con FrameLayout. FrameLayout ti consente di aggiungere più viste l'una sull'altra.

Aggiungere un FrameLayout. Al suo interno puoi aggiungere una "vista" e impostarne l'altezza e la larghezza su match_parent. In cima alla vista, aggiungi i pulsanti che desideri.

Quindi nel codice, ottenere il riferimento della vista e impostare onClickListener su di esso in modo che ogni volta che l'utente tocca tale vista, è possibile gestire tale evento. Imposta anche i listener dei clic sugli altri pulsanti.

Ora gestisci i tuoi eventi touch. Ora saprai se l'utente ha fatto clic sul pulsante o all'esterno (l'utente ha fatto clic sulla vista).

Se si desidera creare pulsanti trasparenti o traslucidi, selezionare https://stackoverflow.com/a/11689915/1117338. Spero che questo aiuti.

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

In questo modo è possibile ottenere il valore alfa del pixel toccati. Ora puoi facilmente verificare se il pixel toccato è trasparente o meno.

+0

questo in realtà sembra promettente! dovrò verificarlo prima di spuntare la risposta, però. potrebbe esserci un problema: cosa accadrebbe su schermi di dispositivi diversi (densità/risoluzioni diverse)? funzionerà ancora? inoltre, questo metodo utilizza più memoria in questo modo per la bitmap? –

+0

funzionerà anche se non utilizzo una bitmap per essere mostrata nella vista? –

+0

Se stai progettando per schermi diversi, devi comunque usare i frammenti. E per quanto riguarda la bitmap, penso che l'uso di un'immagine di pulsante semplice non utilizzi molta memoria poiché può essere facilmente ridimensionata senza perdere molti dettagli. Infine, sì, è possibile utilizzare il metodo drawbitmap, ma ciò richiederebbe una tela, quindi consiglio di utilizzare invece una vista grafica. –

Problemi correlati