Метод Android onClick не работает на пользовательском представлении

Я начал работать над приложением. Я создаю меню вчера, но метод onClick не работает! Я создал класс, который расширяет представление и вызывает ее MainMenuObject – этот класс предназначен для любого объекта в главном меню (кнопки, логотипы и т. Д.). Я создал для них специальный класс, потому что я запускаю анимацию при запуске меню. После того как я построил класс MainMenuObject, я построил еще один класс (OpeningTimesView), который расширяет представление и будет иметь все кнопки главного меню в нем и будет функционировать как макет основной деятельности.

Все было хорошо, анимация прошла очень хорошо, и я хотел поместить слушателей на свои кнопки, поэтому я добавил реализацию onClickListener в класс OpenTimesView и переопределил метод onClick. Затем я добавил слушателя к кнопкам с setOnClickListener (this) и setClickable (true), но он не работает! Я пробовал все! Пожалуйста, помогите мне выяснить, что я делаю неправильно. Я добавил тост к методу onClick, который не зависит от какого-либо «if», но он не покажет ни одного.

(Кстати, есть ли способ определить ширину и высоту экрана как переменную, к которой могут обращаться все классы? Она не может быть статичной, потому что вы получаете высоту и ширину от экранного объекта, но должен быть другой способ)

Это код:

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

Спасибо заранее, Элад!

Solutions Collecting From Web of "Метод Android onClick не работает на пользовательском представлении"

У меня была одна и та же проблема – я создал пользовательское представление и когда я зарегистрировал в нем новый Listener, вызвав v.setOnClickListener(new OnClickListener() {...}); Слушателя просто не вызывали.

В моем обычном представлении я также перезаписал public boolean onTouchEvent(MotionEvent event) {...} . Проблема заключалась в том, что я не вызывал метод класса View – super.onTouchEvent(event) . Это решило проблему. Поэтому, если вам интересно, почему ваш слушатель не вызван, вы, вероятно, забыли назвать метод onTouchEvent

Создание пользовательских элементов управления на Android может быть сложным, если вам неудобно работать с UI Framework. Если вы еще этого не сделали, я бы рекомендовал прочитать следующие:

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

Обратите внимание, что когда макеты объявлены в XML, элементы вложены. Это создает иерархию компоновки, которую вы должны создать самостоятельно при настройке компонента с использованием только кода Java.

Скорее всего, вы попадаете в сенсорную иерархию Android. В отличие от некоторых других популярных мобильных платформ, Android предлагает сенсорные события, начиная с вершины иерархии View и прокладывает себе путь вниз. Классы, которые традиционно занимают более высокие уровни иерархии («Активность» и «Макеты»), имеют в них логику для перетасовки, которые они сами не потребляют.

Итак, что бы я рекомендовал делать, это изменить ваш OpeningTimesView чтобы расширить ViewGroup (суперкласс всех макетов Android) или определенный макет ( LinearLayout , RelativeLayout и т. Д.) И добавить ваши кнопки в качестве детей. Прямо сейчас, похоже, не существует определенной иерархии (кнопки на самом деле не «содержатся» в контейнере, они просто члены), что может сбить с толку вопрос о том, где происходят события.

  1. Прикосновения должны естественным образом стекать к кнопкам, позволяя запускать события щелчка
  2. Вы можете использовать механизмы компоновки Android, чтобы нарисовать ваш взгляд, а не полагаться на код рисования, чтобы сделать все это.

Выберите класс макета, чтобы начать с этого, чтобы вы поместили свои кнопки в свои конечные местоположения. Вы можете использовать рамки анимации в Android или пользовательский код рисования (как и сейчас), чтобы оживить их в любом случае до этого момента. Расположение кнопки и где эта кнопка в настоящее время рисуется , при необходимости может быть очень различной, и именно так работает текущая анимационная платформа в Android (до 3.0) … но это отдельная проблема. У вас также есть AbsoluteLayout , который позволяет размещать и заменять объекты в любом месте … но будьте осторожны с тем, как ваше приложение выглядит на всех устройствах Android с этим (учитывая разные размеры экрана).

Что касается вашего второго пункта о информации о дисплее. Самый простой способ – это просто использовать Context.getResources().getDisplayMetrics() где вам это нужно. Activity наследуется из Context , поэтому они могут напрямую вызвать этот метод. В представлениях всегда есть Context вы можете получить доступ с помощью getContext() . Любые другие классы вы можете просто передать Context в качестве параметра в конструкции (это общий шаблон в Android, вы увидите, что для многих объектов требуется Context , в основном для доступа к Resources ).

Вот пример скелета, чтобы начать игру. Это просто выравнивает три горизонтально один раз в качестве конечного местоположения:

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

Вы можете настроить это оттуда. Возможно, начиная с кнопок с видимостью, установленной в View.INVISIBLE, пока вы не активируете их с помощью кода рисования или пользовательского объекта Animation, а затем сделайте их видимыми в конечном месте отдыха.

Ключ здесь, однако, заключается в том, что макет достаточно умен, чтобы знать, что когда он получает событие касания, он должен перенаправить его соответствующему ребенку. Вы можете создать пользовательский вид без этого, но вам придется перехватывать все касания в контейнере и выполнять математику, чтобы определить, к какому подразделению нужно вручную переслать событие. Если вы действительно не можете заставить менеджера компоновки работать, это ваш регресс.

Надеюсь, это поможет!

Вы можете просто вызвать функцию performClick () в onTouchEvent вашего пользовательского представления.

Используйте это в своем пользовательском представлении:

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

Внедрите onClickListener в классе onClickListener , так как это объекты, которые будут реагировать на клики.
Другой альтернативой было бы расширить Button вместо View , потому что вы используете только кнопки там


Обновление: полный пример


Это идея реализовать его непосредственно в интерактивных представлениях. Существует класс TestView который расширяет View и переопределяет onDraw , как вам нужно, а также отвечает на клики. Я оставил любую анимационную реализацию, поскольку у вас есть эта часть, и это не относится к обсуждению ClickListener .
Я тестировал его в эмуляторе Eclair, и он работает так, как ожидалось (сообщение Toast после щелчка).

Файл: 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); } } 

Файла: 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); } } 

Если вам требуется несколько кликов, а некоторые не доступны для кликов, вы можете добавить конструктор с логическим аргументом, чтобы определить, прикреплен ли ClickListener или нет в представлении:

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

Вы должны вызвать setOnClickListener(this) в contructor (s) и реализовать View.OnClickListener на себе.

В этом случае:

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

У меня есть решение! На самом деле это не решение этой конкретной проблемы, а совершенно новый подход. Я отправил эту тему кому-то, кого знаю, и он сказал мне использовать Анимационный SDK, который имеет андроид (например, Wireless Designs), поэтому вместо того, чтобы делать главную страницу меню с 4 классами, я делаю это только с одним классом, который расширяется Активность и класс анимации предлагает множество вариантов анимации. Я хочу поблагодарить вас обоих за то, что вы помогли мне, вы здоровы. Я добавляю код, если кто-то встретит этот поток с той же проблемой или что-то еще:

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

Я делаю это так:

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