Il metodo Android onClick non funziona in una vista personalizzata

Ho iniziato a lavorare su un'app. Creo il menu ieri, ma il metodo onClick non funziona! Ho creato una class che estende la vista e lo ha chiamato MainMenuObject – quella class è per qualsiasi object nel menu principale (pulsanti, loghi ecc.). Ho creato una class speciale per loro perché sto facendo un'animation quando il menu inizia. Dopo aver costruito la class MainMenuObject ho costruito un'altra class (OpeningTimesView) che estende la vista e avrà tutti i pulsanti del menu principale in essa e functionrà come layout dell'attività principale.

Tutto era buono, l'animation è andata molto bene e volevo mettere gli ascoltatori sui miei pulsanti, quindi ho aggiunto una implementazione di onClickListener alla class OpeningTimesView e ho superato il metodo onClick. Poi ho aggiunto l'ascoltatore ai pulsanti con setOnClickListener (this) e setClickable (true), ma non funziona! Ho provato tutto! Aiutaci a capire cosa faccio male. Ho aggiunto un toast al metodo onClick che non dipende da alcuna "if", ma non sarà mostrato.

  • Recupera i dettagli utente di Facebook in android
  • Le opzioni di avvio di Android Emulator non funzionano in plugin Eclipse?
  • Pulsanti in una formazione del cerchio
  • Android Wi-Fi Direct: onPeersAvailable
  • Gestori di exception globali in Java
  • Nell'app Google Play, come viene visualizzata l'implementazione dell'elenco ViewGroup?
  • (BTW c'è un modo per definire la width e l'altezza dello schermo come variabile che tutte le classi possono accedere? Non può essere statica perché si ottiene l'altezza e la width da un object di visualizzazione, ma deve essere un altro modo)

    questo è il codice:

    public class OpeningTimesView extends View implements OnClickListener{ private MainMenuObjectView searchButton; private MainMenuObjectView supportButton; private MainMenuObjectView aboutButton; private int screenWidth; private int screenHeight; public OpeningTimesView(Context context, Display dis) { super(context); this.screenWidth = dis.getWidth(); this.screenHeight = dis.getHeight(); searchButton = new MainMenuObjectView(context, 200, MovingMode.RIGHT, R.drawable.search, dis); supportButton = new MainMenuObjectView(context, 400, MovingMode.LEFT, R.drawable.support, dis); aboutButton = new MainMenuObjectView(context, 600, MovingMode.RIGHT, R.drawable.about, dis); searchButton.setClickable(true); supportButton.setClickable(true); aboutButton.setClickable(true); searchButton.setOnClickListener(this); supportButton.setOnClickListener(this); aboutButton.setOnClickListener(this); } @Override public void onClick(View view){ Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show(); if(view == searchButton){ Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show(); } else if(view == supportButton){ Toast.makeText(getContext(), "Support button pressed", Toast.LENGTH_SHORT).show(); } else Toast.makeText(getContext(), "About button pressed", Toast.LENGTH_SHORT).show(); } @Override public void onDraw(Canvas canvas) { // Drawing the buttons this.searchButton.onDraw(canvas); this.aboutButton.onDraw(canvas); this.supportButton.onDraw(canvas); } 

    Grazie in anticipo, Elad!

    7 Solutions collect form web for “Il metodo Android onClick non funziona in una vista personalizzata”

    Ho avuto lo stesso problema – ho creato una vista personalizzata e quando ho registrato un nuovo listener per l'attività chiamando v.setOnClickListener(new OnClickListener() {...}); l'ascoltatore non è stato chiamato.

    Nella mia vista personalizzata ho anche sovrascritto il public boolean onTouchEvent(MotionEvent event) {...} . Il problema è che non ho chiamato il metodo della class View – super.onTouchEvent(event) . Questo ha risolto il problema. Quindi, se vi state chiedendo perché il tuo ascoltatore non viene chiamato, hai probabilmente dimenticato di call il metodo superclass onTouchEvent

    La creazione di controlli personalizzati in Android può risultare difficile se non è comodo con come funziona il Framework UI. Se non lo hai già fatto, consiglio di leggerle:

    http://developer.android.com/guide/topics/ui/declaring-layout.html

    http://developer.android.com/guide/topics/ui/custom-components.html

    http://developer.android.com/guide/topics/ui/layout-objects.html

    Si noti che quando i layout vengono dichiarati in XML, gli elementi vengono annidati. In questo modo viene creata una gerarchia di layout che è necessario creare la propria personalità quando si personalizza un componente utilizzando solo codice Java.

    Molto probabilmente si sta avvicinando alla gerarchia touch di Android. A differenza di altre piattaforms mobili popolari, Android offre events touch che partono dalla parte superiore della gerarchia di View e funziona verso il basso. Le classi che occupano tradizionalmente i livelli più alti della gerarchia (Attività e Layout) hanno logica in loro per avanzare tocchi che non consumano.

    Quindi, quello che vorrei fare è cambiare il tuo OpeningTimesView per estendere un ViewGroup (la superclass di tutti i layout Android) o un layout specifico ( LinearLayout , RelativeLayout , ecc.) E aggiungere i pulsanti come bambini. Al momento, non sembra che ci sia una gerarchia definita (i pulsanti non sono realmente "contenuti" nel contenitore, sono solo membri) che possono confondere la questione di where gli events stanno realmente andando.

    1. I tocchi dovrebbero più naturalmente scorrere verso i pulsanti, consentendo l'triggerszione degli events clic
    2. Puoi approfittare dei meccanismi di layout di Android per disegnare la vista anziché fare affidamento sul codice di disegno per fare tutto ciò.

    Scegli una class di layout per iniziare con quella che ti aiuterà a posizionare i pulsanti nelle loro posizioni FINALI . Puoi utilizzare il framework di animation in Android o il codice di disegno personalizzato (come adesso) per animarli comunque che ti piace fino a quel momento. La posizione di un button e where il button è attualmente disegnata può essere molto diversa se necessario, e questo è come funziona l'attuale Framework di Animazione in Android (prima di 3.0) … ma questo è un problema distinto. Hai anche AbsoluteLayout , che ti permette di inserire e sostituire oggetti ovunque ti piaccia … ma fai attenzione a come la tua applicazione guarda su tutti i dispositivi Android con questa (a seconda delle size dello schermo).

    Per quanto riguarda il secondo punto circa informazioni sul display. Il metodo più semplice è probabilmente solo utilizzare Context.getResources().getDisplayMetrics() ovunque tu sia necessario. Activity eredita da Context , in modo da poter call direttamente questo metodo. Le viste hanno sempre un Context è ansible accedere con getContext() . Tutte le altre classi che puoi passare il Context come parametro in costruzione (questo è un model comune in Android, vedrai che molti oggetti richiedono un Context , principalmente per accedere a Resources ).

    Ecco un esempio di scheletro per saltare le cose di avvio. Questo solo le righe tre in orizzontale una volta come luogo finale:

     Public class OpeningTimesView extends LinearLayout implements OnClickListener { private MainMenuObjectView searchButton; private MainMenuObjectView supportButton; private MainMenuObjectView aboutButton; private int screenWidth; private int screenHeight; public OpeningTimesView(Context context) { this(context, null); } //Thus constructor gets used if you ever instantiate your component from XML public OpeningTimesView(Context context, AttributeSet attrs) { super(context, attrs); /* This is a better way to obtain your screen info DisplayMetrics display = context.getResources().getDisplayMetrics(); screenWidth = display.widthPixels; screenHeight = display.heightPixels; */ //This way works also, without needing to customize the constructor WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Display dis = wm.getDefaultDisplay(); screenWidth = dis.getWidth(); screenHeight = dis.getHeight(); searchButton = new MainMenuObjectView(context, 200, MovingMode.RIGHT, R.drawable.search, dis); supportButton = new MainMenuObjectView(context, 400, MovingMode.LEFT, R.drawable.support, dis); aboutButton = new MainMenuObjectView(context, 600, MovingMode.RIGHT, R.drawable.about, dis); //Even if they don't extend button, if MainMenuObjectView is always clickable // this should probably be brought into that class's constructor searchButton.setClickable(true); supportButton.setClickable(true); aboutButton.setClickable(true); searchButton.setOnClickListener(this); supportButton.setOnClickListener(this); aboutButton.setOnClickListener(this); //Add the buttons to the layout (the buttons are now children of the container) setOrientation(LinearLayout.HORIZONTAL); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); addView(searchButton, params); addView(supportButton, params); addView(aboutButton, params); } @Override public void onClick(View view){ Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show(); if(view == searchButton){ Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show(); } else if(view == supportButton){ Toast.makeText(getContext(), "Support button pressed", Toast.LENGTH_SHORT).show(); } else Toast.makeText(getContext(), "About button pressed", Toast.LENGTH_SHORT).show(); } @Override public void onDraw(Canvas canvas) { //Drawing the buttons // This may only be necessary until they are in place, then just call super.onDraw(canvas) this.searchButton.onDraw(canvas); this.aboutButton.onDraw(canvas); this.supportButton.onDraw(canvas); } } 

    Puoi personalizzare questo da lì. Forse avviando i pulsanti con visibilità impostati su View.INVISIBLE finché non li animerai con il codice di disegno o con un object di animation personalizzato, quindi renderli visibili nel loro posto di rest finale.

    La chiave qui, però, è il layout è abbastanza intelligente per sapere che quando riceve un evento di touch dovrebbe essere inoltrata al bambino corrispondente. Puoi creare una visualizzazione personalizzata senza questo, ma dovrai intercettare tutti i tocchi sul contenitore e fare la math per determinare quale sottosquadra per inoltrare manualmente l'evento. Se davvero non puoi fare alcun lavoro di layout manager, questo è il tuo ricorso.

    Spero possa aiutare!

    Puoi call solo performClick () in onTouchEvent della tua visualizzazione personalizzata.

    Utilizza questa visualizzazione personalizzata:

      @Override public boolean onTouchEvent(final MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_UP){ return performClick(); } return true; } 

    Implementare l' onClickListener nella class MainMenuObjectView , poiché questi sono gli oggetti che rispondono ai clic.
    Un'altra alternativa sarebbe quella di estendere Button invece di View , perché utilizzi solo pulsanti lì


    Aggiornamento: esempio completo


    Questa è l'idea di implementarla direttamente nelle viste cliccabili. Esiste una class TestView che estende la View e sovrascrive onDraw , come è necessario, e risponde anche ai clic. Ho lasciato fuori qualsiasi implementazione di animation in quanto hai questa parte e non è rilevante per la discussione ClickListener .
    Ho testato in un emulatore Eclair e funziona come previsto (un messaggio di Toast dopo un click).

    file: Test.java

     package com.aleadam.test; import android.app.Activity; import android.os.Bundle; import android.widget.LinearLayout; import android.widget.TextView; public class Test extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout ll = new LinearLayout(this); ll.setOrientation(LinearLayout.VERTICAL); TextView label = new TextView(this); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); label.setText("Click the circle!"); TestView testView = new TestView(this); ll.addView(label, layoutParams); ll.addView(testView, layoutParams); setContentView(ll); } } 

    file: TestView.java

     package com.aleadam.test; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; public class TestView extends View implements OnClickListener { Context context; public TestView(Context context) { super(context); this.context = context; setOnClickListener(this); } public void onClick(View arg0) { Toast.makeText(context, "View clicked.", Toast.LENGTH_SHORT).show(); } @Override public void onDraw (Canvas canvas) { super.onDraw(canvas); this.setBackgroundColor(Color.LTGRAY); Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.RED); canvas.drawCircle(20, 20, 20, paint); } } 

    Se hai bisogno di alcuni clic e alcuni non cliccabili, puoi aggiungere un constructor con un argomento boolean per determinare se il ClickListener è collegato o less alla vista:

     public TestView(Context context, boolean clickable) { super(context); this.context = context; if (clickable) setOnClickListener(this); } 

    Devi call setOnClickListener(this) in contructor (s) e implementare View.OnClickListener su auto.

    In questo modo:

     public class MyView extends View implements View.OnClickListener { public MyView(Context context) { super(context); setOnClickListener(this); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); setOnClickListener(this); } @Override public void onClick(View v) { Toast.makeText(getContext(), "On click.", Toast.LENGTH_SHORT).show(); } } 

    Ho una soluzione! Non è una soluzione per questo problema specifico, ma un approccio completamente nuovo. Ho inviato questo thread a qualcuno che conosco e mi ha detto di usare l'SDK di Animazione che l'android ha (come i Design Wireless), per cui, invece di fare la pagina del menu principale con 4 classi, lo faccio solo con una class che si estende Attività e la class Animazione offre molte opzioni di animation. Voglio ringraziarvi per aiutarmi, sei fantastico. Sto aggiungendo il codice se qualcuno incontrerà questo thread con lo stesso problema o qualcosa del genere:

     package elad.openapp; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.HapticFeedbackConstants; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.Toast; public class OpeningTimes extends Activity implements OnClickListener{ /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Disabling the title bar.. requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); // Create the buttons and title objects ImageView title = (ImageView)findViewById(R.id.title_main); ImageView search = (ImageView)findViewById(R.id.search_button_main); ImageView support = (ImageView)findViewById(R.id.support_button_main); ImageView about = (ImageView)findViewById(R.id.about_button_main); // Setting the onClick listeners search.setOnClickListener(this); support.setOnClickListener(this); about.setOnClickListener(this); setButtonsAnimation(title, search, support, about); } @Override public void onClick(View v) { if(v.getId()==R.id.search_button_main){ v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); startActivity(new Intent(this,SearchPage.class)); } else if(v.getId()==R.id.support_button_main){ v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); Toast.makeText(this, "Coming soon...", Toast.LENGTH_LONG).show(); } else if(v.getId()==R.id.about_button_main){ v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); Toast.makeText(this, "Coming soon...", Toast.LENGTH_LONG).show(); } } // Setting the animation on the buttons public void setButtonsAnimation(ImageView title, ImageView search, ImageView support, ImageView about){ // Title animation (two animations - scale and translate) AnimationSet animSet = new AnimationSet(true); Animation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f); anim.setDuration(750); animSet.addAnimation(anim); anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f); anim.setDuration(750); animSet.addAnimation(anim); title.startAnimation(animSet); // Search button animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1.5f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f); anim.setDuration(750); search.startAnimation(anim); // Support button animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1.5f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f); anim.setDuration(750); support.startAnimation(anim); // About button animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 3f, Animation.RELATIVE_TO_SELF, 0.0f); anim.setDuration(750); about.startAnimation(anim); } } 

    Lo faccio così:

     public class YourView extends LinearLayout implements OnClickListener { OnClickListener listener; //... constructors public void setOnClickListener(OnClickListener listener) { this.listener = listener; } @Override public void onClick(View v) { if (listener != null) listener.onClick(v); } } 
    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.