One of the primary means for the user to interact with the device is through touch. Often, this is the only way as there is no keyboard or mouse, and other methods might be unavailable or undesirable.
All views provide access to the two most common forms of touch input: single taps and long presses. We respond to these events using either listeners or event handlers:
Click
event:view.Click += (sender, e) => { // the user tapped the view };
LongClick
event. To prevent the Click
event from also being triggered, we ensure that the Handled
property of the EventArgs
is set to true
:view.LongClick += (sender, e) => { // the user long-pressed on the view e.Handled = true; };
Both the Click
and LongClick
events can also be subscribed to using listeners:
Click
event, we ensure that we implement the View.IOnClickListener
interface:public class MyView : View, View.IOnClickListener { public void OnClick(View view) { // the user tapped the view } }
SetOnClickListener()
method:SetOnClickListener(this);
LongClick
events can also be subscribed to using listeners. To do this, we implement the View.IOnLongClickListener
interface:public class MyView : View, View.IOnLongClickListener { public bool OnLongClick(View view) { // the user long-pressed the view return true; } }
SetOnLongClickListener()
method:SetOnLongClickListener(this);
There are many ways to interact with apps running on a device. One of the most common ways is touch. Most Android smartphones are built with large, touchscreens which are the primary source of input.
Touch input can range from simple, single taps all the way to multifinger gestures. The simplest and most common are single taps and longpresses. Both forms are very easy to implement, requiring only logic to be attached to the Click
event, for single taps, and the LongClick
event, for longpress gestures.
Both events will fire as soon as the user completes the touch, but in the case of a long-press, we have to ensure that we let the event system know that we are handling a longpress instead of a single tap.
We let the system know that we are handling the long-press by setting the value of the Handled
property on the LongClickEventArgs
parameter of the LongClick
event to true
. If we do not do this, the Click
event will also be raised, possibly resulting in unexpected behavior.
Both the Click
and LongClick
events can also be handled using Java-style listeners. The listener interface for the Click
event is View.IOnClickListener
and View.IOnLongClickListener
for the LongClick
event. Instances of classes implementing the interfaces are passed to the SetOnClickListener()
and SetOnLongClickListener()
methods.
Because the events actually use the listeners under the covers, attaching a handler to the event will disconnect the listeners. Also, assigning a listener to the view will detach the events. As a result, only one form of handler can be used at a time.
Sometimes, we need more advanced touch events, such as the number of fingers on the screen and their position on the screen. We get all the touch data by overriding the OnTouchEvent()
method and accessing the MotionEvent
argument:
public class MyView : View { public override bool OnTouchEvent(MotionEvent e) { return base.OnTouchEvent(e); } }
Every time a touch event is triggered, we can access the data related to the touch using the MotionEvent
argument. This instance contains data such as the number of fingers touching the screen, in the PointerCount
property, and the location of each finger, through the GetX()
and GetY()
methods. We use the ActionMasked
property to determine what raised the event. Possible reasons for touch events could be that a finger was either added, removed, or moved over the screen.
We can use this data to interpret gestures such as zoom, rotate, or drag. Here, we store all the fingers in a dictionary, along with their position on the screen:
var pointerIndex = e.ActionIndex; var pointerId = e.GetPointerId(pointerIndex); switch (e.ActionMasked) { case MotionEventActions.Down: case MotionEventActions.PointerDown: pointers[pointerId] = new PointF(e.GetX(pointerIndex), e.GetY(pointerIndex)); break; case MotionEventActions.Move: for (int i = 0; i < e.PointerCount; i++) { var id = e.GetPointerId(i); pointers[id] = new PointF(e.GetX(i), e.GetY(i)); } break; case MotionEventActions.Up: case MotionEventActions.PointerUp: case MotionEventActions.Cancel: pointers.Remove(id); break; }