blob: cd2b4813cf83461610203b1e8ea8f6647e5b9677 [file] [log] [blame]
page.title=События ввода
parent.title=Пользовательский интерфейс
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Содержание документа</h2>
<ol>
<li><a href="#EventListeners">Приемники событий</a></li>
<li><a href="#EventHandlers">Обработчики событий</a></li>
<li><a href="#TouchMode">Режим касания</a></li>
<li><a href="#HandlingFocus">Фокус обработки</a></li>
</ol>
</div>
</div>
<p>В системе Android предусмотрено несколько способов перехвата событий взаимодействия пользователя с вашим приложением.
Что касается событий в пользовательском интерфейсе, подход состоит в том, чтобы захватывать события из
определенного представления объекта, с которым взаимодействует пользователь. Класс отображаемых объектов (View) содержит средства, позволяющие делать это.</p>
<p>В различных классах View, которые вы будете использовать для создания макета, вы заметите несколько общедоступных методов обратного вызова,
полезных для работы с событиями пользовательского интерфейса. Эти методы вызываются платформой Android, когда
с этим объектом выполняется соответствующее действие. Например, когда пользователь касается отображаемого объекта (кнопки),
вызывается метод <code>onTouchEvent()</code> этого объекта. Однако для перехвата этого события вы должны
наследовать класс и переопределить метод. Однако наследование каждого отображаемого объекта
для обработки такого события было бы неудобно. Именно поэтому класс View также содержит
набор вложенных интерфейсов с обратными вызовами, которые можно задать значительно проще. Эти интерфейсы,
которые называются <a href="#EventListeners">приемниками событий</a>, и служат перехватчиками действий пользователя с вашим пользовательским интерфейсом.</p>
<p>Несмотря на то, что вы будете чаще использовать приемники событий для перехвата действий пользователя, может
наступить момент, когда вам не захочется наследовать класс View, чтобы создать нестандартный компонент.
Возможно, вы захотите наследовать класс {@link android.widget.Button},
чтобы сделать нечто более необычное. В этом случае вы сможете определить поведение события по умолчанию для своего
класса с помощью <a href="#EventHandlers">обработчиков событий</a> класса.</p>
<h2 id="EventListeners">Приемники событий</h2>
<p>Приемник событий — это интерфейс в классе {@link android.view.View}, который содержит один
метод обратного вызова. Эти методы будут вызываться платформой Android, когда в результате взаимодействия пользователя с объектом
пользовательского интерфейса срабатывает отображаемый объект View, в котором зарегистрирован приемник.</p>
<p>Интерфейсы, включенные в приемник события, представляют собой следующие методы обратного вызова:</p>
<dl>
<dt><code>onClick()</code></dt>
<dd>Из объекта {@link android.view.View.OnClickListener}.
Этот метод вызывается, когда пользователь касается элемента
режиме касания), или переводит фокус на элемент с помощью клавиш перемещения или трекбола и
нажимает соответствующую клавишу «ввода» или нажимает на трекбол.</dd>
<dt><code>onLongClick()</code></dt>
<dd>Из объекта {@link android.view.View.OnLongClickListener}.
Этот метод вызывается, когда пользователь касается элемента и удерживает его режиме касания),
или переводит фокус на элемент с помощью клавиш перемещения или трекбола и
нажимает и удерживает соответствующую клавишу «ввода» или трекбол течение одной секунды).</dd>
<dt><code>onFocusChange()</code></dt>
<dd>Из объекта {@link android.view.View.OnFocusChangeListener}.
Этот метод вызывается, когда пользователь перемещается в элемент или из него с помощью клавиш перемещения или трекбола.</dd>
<dt><code>onKey()</code></dt>
<dd>Из объекта {@link android.view.View.OnKeyListener}.
Этот метод вызывается, когда пользователь переносит фокус на элемент и нажимает или отпускает аппаратную клавишу на устройстве.</dd>
<dt><code>onTouch()</code></dt>
<dd>Из объекта {@link android.view.View.OnTouchListener}.
Этот метод вызывается, когда пользователь выполняет действие, считающееся событием касания, например, нажимает, отпускает
или выполняет любой жест на экране пределах границ элемента).</dd>
<dt><code>onCreateContextMenu()</code></dt>
<dd>Из объекта {@link android.view.View.OnCreateContextMenuListener}.
Этот метод вызывается, когда создается контекстное меню результате длительного «длительного нажатия»). См. обсуждение
контекстных меню в руководстве
для разработчиков <a href="{@docRoot}guide/topics/ui/menus.html#context-menu">Меню</a>.</dd>
</dl>
<p>Эти методы являются единственными составными частями соответствующих интерфейсов. Чтобы определить один из этих методов
и обрабатывать события, реализуйте вложенный интерфейс в вашем процесс или определите его, как анонимный класс.
Затем передайте экземпляр реализации
в соответствующий метод <code>View.set...Listener()</code>. (Например, вызовите
<code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>
и передайте ему свою реализацию {@link android.view.View.OnClickListener OnClickListener}.)</p>
<p>В следующем примере показано, как зарегистрировать приемник события «по клику» (on-click) для кнопки. </p>
<pre>
// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
}
};
protected void onCreate(Bundle savedValues) {
...
// Capture our button from layout
Button button = (Button)findViewById(R.id.corky);
// Register the onClick listener with the implementation above
button.setOnClickListener(mCorkyListener);
...
}
</pre>
<p>Возможно, еще удобнее реализовать OnClickListener как часть вашей операции.
При этом исключается дополнительная нагрузка класса и выделение объекта. Например:</p>
<pre>
public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
...
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
}
// Implement the OnClickListener callback
public void onClick(View v) {
// do something when the button is clicked
}
...
}
</pre>
<p>Обратите внимание, что обратный вызов <code>onClick()</code> в примере выше не
содержит возвращаемого значения, но некоторые другие методы приемника события должны возвращать логическое значение. Причина
зависит от события. Для некоторых методов, которые возвращают значения, причина описана ниже:</p>
<ul>
<li><code>{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}</code> —
этот метод возвращает логическое значение, указывающее, что вы обработали это событие и его более не следует хранить.
А именно, верните значение <em>true</em>, чтобы указать, что вы обработали событие и его следует остановить;
верните значение <em>false</em>, если вы не обработали его и/или событие должно продолжаться для любых других
приемников события on-click.</li>
<li><code>{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}</code> —
этот метод возвращает логическое значение, указывающее, что вы обработали это событие и его более не следует хранить.
А именно, верните значение <em>true</em>, чтобы указать, что вы обработали событие и его следует остановить;
верните значение <em>false</em>, если вы не обработали его и/или событие должно продолжаться для любых других
приемников события on-click.</li>
<li><code>{@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}</code> —
этот метод возвращает логическое значение, указывающее, обработал ли ваш приемник это событие. Важно, что
это событие может повлечь несколько действий, следующих друг за другом. Поэтому, если вы возвращаете <em>ложь</em> при приеме
события нажатия, вы указываете, что вы не обработали событие и не
интересуетесь последующими действиями в результате этого события. Соответственно, этот метод не будет вызываться для любых других действий
в рамках этого события, таких как жесты или возможное действие отпускания.</li>
</ul>
<p>Помните, что события аппаратных клавиш всегда попадают в отображаемый объект View, который находится в фокусе. Они отправляются, начиная с верха
в иерархии отображаемых объектов, затем ниже, пока не достигнут соответствующего назначения. Если ваш отображаемый объект (или дочерний объект вашего отображаемого объекта)
находится в фокусе, вы можете видеть, как событие перемещается сквозь метод <code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
dispatchKeyEvent()}</code>. В качестве альтернативы к перехвату событий клавиш через отображаемый объект View можно также получать
все события внутри вашей операции с помощью методов <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
и <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
<p>Кроме того, размышляя о вводе текста для приложения, помните, что многие устройства поддерживают только программные методы
ввода. Такие методы не обязательно основаны на нажатиях клавиш. Некоторые могут использовать голосовой ввод, рукописный ввод и т. д. Даже если
метод ввода представлен интерфейсом, подобным клавиатуре, он обычно <strong>не</strong> приводит к запуску семейства
событий<code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>. Не следует создавать
пользовательский интерфейс, для управления которым требуется нажимать определенные клавиши, кроме случаев, когда вы хотите ограничить использование приложения только устройствами
с аппаратной клавиатурой. В частности, не полагайтесь на эти методы для подтверждения ввода, когда пользователь нажимает
клавишу «Ввод». Вместо этого используйте такие действия, как {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}, чтобы подать методу ввода сигнал
о том, какой реакции ожидает приложение, чтобы он мог соответственно изменить свой пользовательский интерфейс. Избегайте предположений
о работе программного метода ввода и доверьте ему ввод уже отформатированного текста в ваше приложение.</p>
<p class="note"><strong>Примечание.</strong> Система Android сначала будет вызывать обработчики событий, а затем соответствующие обработчики по умолчанию
из определения класса. Поэтому возврат значения <em>истина</em> из этих приемников событий будет останавливать
передачу события остальным приемникам событий, а также будет блокировать обратный вызов
обработчика событий по умолчанию в отображаемом объекте. Поэтому проверьте, что вы хотите прервать событие, когда вы возвращаете значение <em>true</em>.</p>
<h2 id="EventHandlers">Обработчики событий</h2>
<p>Если вы создаете нестандартный компонент из отображаемого объекта, вы сможете определить несколько методов обратного вызова,
используемых как обработчики события по умолчанию.
В документе <a href="{@docRoot}guide/topics/ui/custom-components.html">Нестандартные
компоненты</a> можно узнать о некоторых общих обратных вызовах, используемых для обработки событий,
включая следующие:</p>
<ul>
<li><code>{@link android.view.View#onKeyDown}</code> — вызывается при возникновении нового события клавиши.</li>
<li><code>{@link android.view.View#onKeyUp}</code> — вызывается при возникновении события отпускания клавиши.</li>
<li><code>{@link android.view.View#onTrackballEvent}</code> — вызывается при возникновении события перемещения трекбола.</li>
<li><code>{@link android.view.View#onTouchEvent}</code> — вызывается при возникновении события жеста на сенсорном экране.</li>
<li><code>{@link android.view.View#onFocusChanged}</code> — вызывается, когда отображаемый объект получает или теряет фокус.</li>
</ul>
<p>Существует несколько других методов, о которых следует знать и которые не являются частью класса View,
но могут напрямую влиять на доступные вам способы обработки событий. Поэтому, управляя более сложными событиями внутри
макета, учитывайте и другие методы:</p>
<ul>
<li><code>{@link android.app.Activity#dispatchTouchEvent(MotionEvent)
Activity.dispatchTouchEvent(MotionEvent)}</code> — этот метод позволяет вашей операции {@link
android.app.Activity} перехватывать все события касаний перед их отправкой в окно.</li>
<li><code>{@link android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)
ViewGroup.onInterceptTouchEvent(MotionEvent)}</code> — этот метод позволяет объекту {@link
android.view.ViewGroup} просматривать события перед их отправкой в дочерние отображаемые объекты.</li>
<li><code>{@link android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean)
ViewParent.requestDisallowInterceptTouchEvent(boolean)}</code> — вызовите этот метод
в родительском отображаемом объекте, чтобы указать ему, что он не должен перехватывать события касания с помощью <code>{@link
android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}</code>.</li>
</ul>
<h2 id="TouchMode">Режим касания</h2>
<p>
Когда пользователь перемещается по пользовательскому интерфейсу с помощью клавиш перемещения или трекбола, необходимо
передавать фокус действующим элементам (таким как кнопки), чтобы пользователь мог видеть,
какой элемент будет принимать ввод. Однако, если устройство поддерживает сенсорный ввод, и пользователь
начинает взаимодействовать с интерфейсом, прикасаясь к его элементам, исчезает необходимость
выделять элементы или передавать фокус определенному отображаемому объекту. Следовательно, существует режим
взаимодействия, который называется «режимом касания».
</p>
<p>
Как только пользователь касается экрана, устройство, поддерживающее сенсорный ввод,
переходит в режим касания. Начиная с этого момента, фокус передается только тем отображаемым объектам, для которых
{@link android.view.View#isFocusableInTouchMode} имеет значение true, таким как виджеты редактирования текста.
Другие отображаемые объекты, которых можно коснуться, например, кнопки, не будут получать фокус при касании. Нажатие будет
просто запускать их приемники событий on-click.
</p>
<p>
В любой момент, когда пользователь нажимает клавишу перемещения или выполняет прокрутку трекболом, устройство
выходит из режима касания и находит отображаемый объект, которому передается фокус. Теперь пользователь может возобновить взаимодействие
с пользовательским интерфейсом без касания экрана.
</p>
<p>
Состояние режима касания поддерживается во всей системе (для всех окон и операций).
Чтобы узнать текущее состояние, можно вызвать
{@link android.view.View#isInTouchMode} и посмотреть, находится ли устройство в режиме касания.
</p>
<h2 id="HandlingFocus">Фокус обработки</h2>
<p>В ответ на пользовательский ввод система обрабатывает обычное перемещение фокуса.
Сюда относится изменение фокуса, когда отображаемые объекты удаляются или скрываются, а также когда становятся доступными
новые отображаемые объекты. Отображаемые объекты сообщают о своей готовности получить фокус
с помощью метода <code>{@link android.view.View#isFocusable()}</code>. Чтобы изменить способность объекта View получать
фокус, вызовите <code>{@link android.view.View#setFocusable(boolean) setFocusable()}</code>. В режиме касания
можно узнать способность отображаемого объекта View получать фокус с помощью метода <code>{@link android.view.View#isFocusableInTouchMode()}</code>.
Для изменения вызовите <code>{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}</code>.
</p>
<p>Перемещение фокуса основано на алгоритме, который находит ближайший элемент
в заданном направлении. В редких случаях алгоритм по умолчанию может не совпадать
с поведением, которое предполагает разработчик. В этих ситуациях можно задать
явное переопределение с помощью следующих атрибутов XML в файле макета:
<var>nextFocusDown</var>, <var>nextFocusLeft</var>, <var>nextFocusRight</var
<var>nextFocusUp</var>. Добавьте один из этих атрибутов в отображаемый объект View, <em>из</em> которого
выходит фокус. Задайте значение атрибута для идентификатора объекта View,
<em>в</em> который следует передать фокус. Например:</p>
<pre>
&lt;LinearLayout
android:orientation="vertical"
... >
&lt;Button android:id="@+id/top"
android:nextFocusUp="@+id/bottom"
... />
&lt;Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
... />
&lt;/LinearLayout>
</pre>
<p>Обычно в этом вертикальном макете перемещение вверх из первой кнопки не должно приводить к перемещению,
как и перемещение вниз из второй кнопки. Теперь, когда верхняя кнопка
задает для нижней кнопки атрибут <var>nextFocusUp</var> наоборот), фокус будет перемещаться
циклически сверху вниз и снизу вверх.</p>
<p>Если вы хотите объявить, что отображаемый объект в вашем пользовательском интерфейсе способен получать фокус (тогда как обычно он не может получать фокус),
добавьте XML-атрибут <code>android:focusable</code> в объект View в объявлении макета.
Установите для него значение <var>true</var>. Можно также объявить объект View,
способным получать фокус в режиме касания с помощью <code>android:focusableInTouchMode</code>.</p>
<p>Чтобы запросить передачу фокуса определенному отображаемому объекту, вызовите <code>{@link android.view.View#requestFocus()}</code>.</p>
<p>Чтобы перехватывать события фокуса (получать уведомления, когда отображаемый объект получает или теряет фокус), используйте метод
<code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code>,
который обсуждается в разделе <a href="#EventListeners">Приемники событий</a> выше.</p>
<!--
<h2 is="EventCycle">Event Cycle</h2>
<p>The basic cycle of a View is as follows:</p>
<ol>
<li>An event comes in and is dispatched to the appropriate View. The View
handles the event and notifies any listeners.</li>
<li>If, in the course of processing the event, the View's bounds may need
to be changed, the View will call {@link android.view.View#requestLayout()}.</li>
<li>Similarly, if in the course of processing the event the View's appearance
may need to be changed, the View will call {@link android.view.View#invalidate()}.</li>
<li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called,
the framework will take care of measuring, laying out, and drawing the tree
as appropriate.</li>
</ol>
<p class="note"><strong>Note:</strong> The entire View tree is single threaded. You must always be on
the UI thread when calling any method on any View.
If you are doing work on other threads and want to update the state of a View
from that thread, you should use a {@link android.os.Handler}.
</p>
-->