Saltar al contenido

El método onClick de Android no funciona en una vista personalizada

Ya no necesitas buscar más por otras webs ya que has llegado al espacio exacto, poseemos la respuesta que quieres sin complicaciones.

Solución:

Acabo de tener el mismo problema: creé una vista personalizada y cuando registré un nuevo oyente en la actividad llamando v.setOnClickListener(new OnClickListener() ...); el oyente simplemente no fue llamado.

En mi vista personalizada también sobrescribí el public boolean onTouchEvent(MotionEvent event) ... método. El problema fue que no llamé al método de la clase View – super.onTouchEvent(event). Eso resolvió el problema. Entonces, si se está preguntando por qué no se llama a su oyente, probablemente se haya olvidado de llamar a las superclase onTouchEvent método

A continuación, se muestra un ejemplo sencillo:

private static class CustomView extends View implements View.OnClickListener 
    public CustomView(Context context) 
        super(context);
    

    @Override
    public boolean onTouchEvent(MotionEvent event) 
        super.onTouchEvent(event);   // this super call is important !!!
        // YOUR LOGIC HERE
        return true;
    

    @Override
    public void onClick(View v) 
        // DO SOMETHING HERE
    

Crear controles personalizados en Android puede ser complicado si no se siente cómodo con el funcionamiento de UI Framework. Si aún no lo ha hecho, le recomendaría leer estos:

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

Tenga en cuenta que cuando los diseños se declaran en XML, los elementos están anidados. Esto crea una jerarquía de diseño que debe crear usted mismo al personalizar un componente utilizando solo código Java.

Lo más probable es que esté atrapado en la jerarquía táctil de Android. A diferencia de otras plataformas móviles populares, Android ofrece eventos táctiles que comienzan en la parte superior de la jerarquía de vistas y avanzan hacia abajo. Las clases que tradicionalmente ocupan los niveles más altos de la jerarquía (Actividad y Diseños) tienen lógica en ellas para reenviar toques que ellos mismos no consumen.

Entonces, lo que recomendaría hacer es cambiar su OpeningTimesView extender un ViewGroup (la superclase de todos los diseños de Android) o un diseño específico (LinearLayout, RelativeLayout, etc.) y agregue sus botones como niños. En este momento, no parece haber una jerarquía definida (los botones no están realmente “contenidos” en el contenedor, son solo miembros) lo que puede confundir el problema en cuanto a hacia dónde se dirigen los eventos.

  1. Los toques deberían fluir de forma más natural hacia los botones, permitiendo que se activen los eventos de clic.
  2. Puede aprovechar los mecanismos de diseño de Android para dibujar su vista en lugar de depender del código de dibujo para hacer todo eso.

Elija una clase de diseño para empezar que le ayudará a colocar sus botones en su FINAL ubicaciones. Puede usar el marco de animación en Android o el código de dibujo personalizado (como lo tiene ahora) para animarlos de la forma que desee hasta ese momento. La ubicación de un botón y dónde se encuentra ese botón actualmente dibujado se les permite ser muy diferentes si es necesario, y así es como funciona el marco de animación actual en Android (antes de 3.0) … pero ese es un problema aparte. Tu también tienes AbsoluteLayout, que le permite colocar y reemplazar objetos en cualquier lugar que desee … pero tenga cuidado con el aspecto de su aplicación en todos los dispositivos Android con esta (dados los diferentes tamaños de pantalla).

En cuanto a su segundo punto sobre la información de visualización.
El método más simple probablemente sea usar Context.getResources().getDisplayMetrics() donde lo necesite. Activity hereda de Context, para que puedan llamar a este método directamente. Las vistas siempre tienen un Context puedes acceder con getContext(). Cualquier otra clase, simplemente puede pasar el Context como un parámetro en la construcción (este es un patrón común en Android, verá que muchos objetos requieren un Context, principalmente para acceder Resources).

Aquí hay un ejemplo de esqueleto para poner en marcha las cosas. Esto solo alinea los tres horizontalmente una vez como ubicación final:

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

Puedes personalizar esto desde allí. Tal vez inicie los botones con la visibilidad configurada en View.INVISIBLE hasta que los anime con su código de dibujo o un objeto de animación personalizado, y luego los haga visibles en su lugar de descanso final.

los key aquí, sin embargo, es el diseño lo suficientemente inteligente como para saber que cuando recibe un evento táctil se supone que lo reenvía al niño correspondiente. Puede crear una vista personalizada sin esto, pero tendrá que interceptar todos los toques en el contenedor y hacer los cálculos para determinar a qué subvista reenviar manualmente el evento. Si realmente no puede hacer que ningún administrador de diseño funcione, este es su recurso.

¡Espero que ayude!

Puede simplemente llamar a performClick () en onTouchEvent de su vista personalizada.

Use esto en su vista personalizada:

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

Si entiendes que te ha sido de provecho nuestro post, sería de mucha ayuda si lo compartes con otros seniors de esta manera contrubuyes a difundir esta información.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *