SoFunction
Updated on 2025-04-09

IOS development of touch events detailed introduction

IOS Touch Events

Events in iOS can be divided into 3 types:

  1. Touch Events
  2. Accelerometer events
  3. Remote control events

Responder object

Not any object can handle events in iOS. Only objects that inherit UIResponder can receive and process events. We call it the “responder object.”
UIApplication, UIViewController, and UIView all inherit from UIResponder, so they are all responder objects and can receive and process events.

UIResponder provides the following methods to handle events

Touch events (corresponding to Android action_down, action_move, action_up, action_cancel)

- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event; 
- (void)touchesMoved:(NSSet )touches withEvent:(UIEvent )event; 
- (void)touchesEnded:(NSSet )touches withEvent:(UIEvent )event; 
- (void)touchesCancelled:(NSSet )touches withEvent:(UIEvent )event;

Accelerometer event (kind of like android sensor)

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event; 
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event; 
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

Remote control events

- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

UIView's touch event handling

UIView is a subclass of UIResponder, which can override the following 4 methods to handle different touch events.

One or more fingers start to touch the view, and the system will automatically call the following method of the view

- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event

If one or more fingers move on the view, the system will automatically call the following method of the view (the method will be continuously called as the finger moves)

- (void)touchesMoved:(NSSet )touches withEvent:(UIEvent )event

One or more fingers leave the view, the system will automatically call the following method of the view

- (void)touchesEnded:(NSSet )touches withEvent:(UIEvent )event

Before the touch is over, a system event (such as incoming call) will interrupt the touch process, and the system will automatically call the following method of the view.

- (void)touchesCancelled:(NSSet )touches withEvent:(UIEvent )event

All UITouch objects are stored in touches.

When a user touches the screen with one finger, a UITouch object associated with the finger is created, and a finger corresponds to a UITouch object.

The role of UITouch

Save information related to the finger, such as the location, time, and stage of the touch. When the finger moves, the system will update the same UITouch object so that it can save the touch position of the finger all the time. When the finger leaves the screen, the system will destroy the corresponding UITouch object.

Properties of UITouch

The window in which the touch is generated
@property(nonatomic,readonly,retain) UIWindow *window;
The view in which the touch is generated
@property(nonatomic,readonly,retain) UIView  *view;
Number of times the screen is tapped in a short time,Can be based ontapCountJudgment click、Double-click or more clicks
@property(nonatomic,readonly) NSUInteger tapCount;
Records the time when the touch event occurs or changes,Unit is seconds
@property(nonatomic,readonly) NSTimeInterval  timestamp;
The current state of the touch event
@property(nonatomic,readonly) UITouchPhase phase;

- (CGPoint)locationInView:(UIView *)view;
The return value indicates that the touch isviewLocation on
The returned location here is forviewof coordinate system(byviewThe upper left corner is the origin(0, 0))
Passed in during callviewThe parameters arenilWord,The touch point is returnedUIWindowLocation
- (CGPoint)previousLocationInView:(UIView *)view;
该方法记录了前一个触摸点Location

Customize the drag and drop effect of the control

ios:

1. Custom view inherits from UIView

2. Overwrite touchesMoved to implement specific logic

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{

 //Get UITouch object UITouch *touch = [touches anyObject];
 //Get the previous point CGPoint p = [touch previousLocationInView:self];
 //Get the current point CGPoint currp = [touch locationInView:self];
 //Produce translation and drag effect  = CGAffineTransformTranslate(,  - ,  - );

}

android:

1. Custom view inherits from View

2. Overwrite onTouchEvent to implement specific logic

private int x, y;
@Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (()){
   case MotionEvent.ACTION_DOWN:
    x = (int) ();
    y = (int) ();
    break;
   case MotionEvent.ACTION_MOVE:
    int mx = (int)();
    int my = (int)();

//    setTranslationX(getTranslationX()+mx-x);
//    setTranslationY(getTranslationY()+my-y);

    layout(getLeft()+mx-x,getTop()+my-y,getLeft()+getMeasuredWidth()+mx-x,getTop()+getMeasuredHeight()+my-y);

    x = mx;
    y = my;
    break;
  }
  return true;
 }

UIGestureRecognizer

After iOS 3.2, Apple launched the gesture recognition function (Gesture Recognizer). In terms of touch event processing, UIGestureRecognizer can easily identify some common gestures made by users on a view.

UIGestureRecognizer

UIGestureRecognizerIt's an abstract class,Defines the basic behavior of all gestures,Use its subclass to handle specific gestures
UITapGestureRecognizer(tap)
UIPinchGestureRecognizer(Pinch,For zoom)
UIPanGestureRecognizer(Drag and drag)
UISwipeGestureRecognizer(Swipe lightly)
UIRotationGestureRecognizer(Rotate)
UILongPressGestureRecognizer(Long press)

The usage of gesture recognizer is similar. For example, the usage steps of UITapGestureRecognizer are as follows:

//Create a gesture recognizer objectUITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
//Set specific properties of gesture recognizer object// Tap twice in a row = 2;
// 2 fingers are required to tap together = 2;
//Add gesture recognizer to the corresponding view[ addGestureRecognizer:tap];
Triggering of monitor gestures
[tap addTarget:self action:@selector(tapIconView:)];

The drag and drop effect above can also be achieved in this way:

//Called when the page is loaded- (void)viewDidLoad {
 [super viewDidLoad];
 //Create a gesture recognizer object  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
 //Add gesture recognizer to the corresponding view [ addGestureRecognizer:pan];
}

- (void)pan:(UIPanGestureRecognizer *)pan
{
 // Get the touch point of gesture // CGPoint curP = [pan locationInView:];

 // Get the movement of the gesture, which is also relative to the initial position CGPoint transP = [pan translationInView:];

  = CGAffineTransformTranslate(, , );

 // Reset [pan setTranslation:CGPointZero inView:];
 //Judge the current finger status //if ( == UIGestureRecognizerStateBegan) {// When pressing the finger, it is similar to ACTION_DOWN in Android //}
}

The corresponding UIGestureRecognizerState has the following states:

// No touch event occurs, the default state of all gesture recognition UIGestureRecognizerStatePossible,
 // When a gesture has begun but has not changed or has been completed UIGestureRecognizerStateBegan,
 // Change of gesture status UIGestureRecognizerStateChanged,
 // gesture completed UIGestureRecognizerStateEnded,
 // The gesture is cancelled and restored to Possible state UIGestureRecognizerStateCancelled, 
 // The gesture fails and returns to Possible state UIGestureRecognizerStateFailed,
 // Identify gesture recognition UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded 

Note: Multiple gestures are not supported by default, that is, they cannot be scaled and rotated simultaneously by default. If you want to support multiple gestures, you need to implement the UIGestureRecognizerDelegate proxy method: shouldRecognizeSimultaneouslyWithGestureRecognizer method:

#pragma mark - Gesture Proxy Method// Whether to enable triggering gestures//- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
//{
// return NO;
//}

// Whether to support multiple gestures at the same time, the default is that multiple gestures are not supported// Return to yes to support multiple gestures- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
 return YES;
}

// Whether to accept finger touch points//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
// // Get the current touch point// CGPoint curP = [touch locationInView:];
//  return YES;
//}

Event delivery

How can a view not handle events:

userInteractionEnabled = NO,hidden = YES,alpha <= 0.01

UIImageView does not allow user interaction by default, so the child controls on it cannot receive events by default.

Find the most suitable view through recursion

The first control to receive events is a window. When the event is passed to the window, the window will find the most suitable view.

1. Determine whether you can receive events
2. Click on the window not
3. Find a more suitable view than yourself, traverse the subcontrol from behind to front, and after getting the subcontrol, pass the event to this subcontrol
4. After the child control gets the event, it will make the same judgment and keep searching recursively until it finds the most suitable view.
The purpose of event delivery is to find the most suitable view and hand it over to him.

HitText method and pointInside method

// Called when event is passed// When the event is passed to the control, this method of the control will be called to find the most suitable view// point: the current touch point, the coordinate system of point point is the method caller- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
 // The method of calling the system is to find the most suitable view and return the most suitable view UIView *fitView = [super hitTest:point withEvent:event];

// NSLog(@"fitView--%@",fitView);
 return fitView;
}

// Function: determine whether the current point is on the method caller (control)- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
 return YES;
}

The underlying implementation of hitTest

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{

 // 1. Determine whether the current control can receive events if ( == NO ||  == YES ||  &lt;= 0.01) return nil;

 // 2. Whether the point is in the current control if ([self pointInside:point withEvent:event] == NO) return nil;

 // 3. traverse your own child control from behind to front NSInteger count = ;

 for (NSInteger i = count - 1; i &gt;= 0; i--) {
  UIView *childView = [i];

  // Convert the coordinate system on the current control to the coordinate system on the subcontrol  CGPoint childP = [self convertPoint:point toView:childView];

  UIView *fitView = [childView hitTest:childP withEvent:event];


  if (fitView) { // Find the most suitable view   return fitView;
  }
 }
 // The end of the loop means that there is no more suitable view than yourself return self;
}

1. Determine whether the window can handle events? If not, it means that the window is not the most suitable view, and it will not look for a more suitable view than yourself. It will directly return nil and notify UIApplication, and there is no most suitable view.

2. Whether the judgment point is in the window or not

3. Iterate through your own child controls and find if there is a more suitable view than yourself

4. If the child control does not receive events, it means that the child control has not found the most suitable view, and then returns nil, telling the window that the more suitable view has not been found, the window knows that there is no more suitable view than itself, and then handles the event by itself.

The event delivery process of the responder chain

The default approach of touch: don't handle it yourself and leave it to the previous responder.

The previous responder is the parent control by default

  1. If the controller of the view exists, it is passed to the controller; if the controller does not exist, it is passed to its parent view
  2. In the top view of the view hierarchy, if the received event or message is also not able to process it, it passes the event or message to the window object for processing
  3. If the window object is not processed, it passes events or messages to the UIApplication object
  4. If UIApplication also cannot process the event or message, discard it

Thank you for reading, I hope it can help you. Thank you for your support for this site!