Как я могу сделать кнопку более отзывчивой?

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

Когда я нажимаю кнопку, есть небольшая часть задержки (EDIT: я бы оценил около 20-50 мс), прежде чем кнопка загорится в нажатом состоянии. Некоторым приложениям удалось удалить этот бит задержки, например RealCalc (доступный на рынке), кнопки которого переключаются в нажатое состояние сразу после нажатия на них.

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

Мой вопрос: как удалить эту задержку? Я знаю, что я мог бы просто подкласс, переопределить onTouchEvent и перейти оттуда, но я бы предпочел решение, используя только стандартные элементы управления и параметры. Я подозреваю, что решение может также мешать прокрутке, но я могу жить с этим.

EDIT: В частности, указанное отставание - это время, когда вы нажимаете палец на кнопку и удерживаете ее там, пока кнопка не переключится в нажатое состояние. Обработчик onClick вызывается, когда вы снова удаляете палец.

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

Ответ 1

Я вникнул в исходный код Android, чтобы узнать, что происходит.

Оказывается, что класс android.view.View(из которого вызывается Button) переходит в состояние "ПРЕДВАРИТЕЛЬНОЕ" перед переходом в состояние PRESSED:

android.view.View:

1529    /**
1530      * Indicates a prepressed state;
1531      * the short time between ACTION_DOWN and recognizing
1532      * a 'real' press. Prepressed is used to recognize quick taps
1533      * even when they are shorter than ViewConfiguration.getTapTimeout().
1534      * 
1535      * @hide
1536      */
1537     private static final int PREPRESSED             = 0x02000000;

android.view.ViewConfiguration.getTapTimeout() составляет 115 мс на моем Nexus One, что намного длиннее моей оценки.

android.view.ViewConfiguration:

67     /**
68      * Defines the duration in milliseconds we will wait to see if a touch event 
69      * is a tap or a scroll. If the user does not move within this interval, it is
70      * considered to be a tap. 
71      */
72     private static final int TAP_TIMEOUT = 115;

В любом случае, из рассмотрения View.onTouchEvent не похоже, что есть способ избежать этого состояния PREPRESSED с помощью любой стандартной опции. Это настоящий позор.

Хорошей новостью является то, что я теперь подтвердил, что способ избежать этого отставания заключается в подклассе и переопределении onTouchEvent.

Спасибо за обсуждение и ответы.

Ответ 2

Кажется, это исправлено:

public boolean onTouchEvent (MotionEvent event) {
   if (event.getAction() == MotionEvent.ACTION_DOWN) setPressed(true);
   return super.onTouchEvent(event);
}

Все еще не идеально, но лучше.

Ответ 3

Ну... Я обычно расширяю класс Button и переопределяю метод onTouchEvent

public boolean onTouchEvent (MotionEvent event) 
{
   if (event.getAction() == MotionEvent.ACTION_DOWN) 
   {
      setPressed(true);
   }
   return super.onTouchEvent(event);
}

Ответ 4

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