Touch events and gestures developed by iOS
- 2020-06-01 11:02:55
- OfStack
Events in iOS fall into three categories: touch events, accelerometer events, and remote control events. Only objects that inherit from UIResponder can receive and process events, called "responder objects." UIApplication, UIViewController, UIView all inherit from UIResponder. UIResponder internally provides methods to handle events:
Touch events: touchesBegan, touchesMoved, touchesEnded, touchesCancelled
Accelerometer events: motionBegan, motionEnded, motionCancelled
Remote control event: remoteControlReceivedWithEvent
UIVeiw's touch event processing process:
/**
* When the finger begins to touch view Called when the
*
* @param touches <#touches description#>
* @param event <#event description#>
*/
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
/**
* When a finger in view Called when moving up
*
* @param touches <#touches description#>
* @param event <#event description#>
*/
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
/**
* When the fingers are gone view Called when the
*
* @param touches <#touches description#>
* @param event <#event description#>
*/
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
/**
* Called when a touch event is interrupted by a system event
*
* @param touches <#touches description#>
* @param event <#event description#>
*/
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
A touch action must call touchesBeagn, touchesMoved, and touchesEnded.
Speaking of touch methods, the first thing to know is that UITouch is an object. When one finger touches the screen, it generates an UITouch object associated with it, and one finger corresponds to one UITouch object. This object holds the information of this touch, such as the position, time, stage, etc. When the finger moves, the system will update the same UITouch object. Enables it to hold the touch location information of the finger directly. When the finger leaves the screen, the corresponding UITouch object is destroyed.
@interface UITouch : NSObject
@property(nonatomic,readonly) NSTimeInterval timestamp;
@property(nonatomic,readonly) UITouchPhase phase;
@property(nonatomic,readonly) NSUInteger tapCount; // touch down within a certain point within a certain amount of time
// majorRadius and majorRadiusTolerance are in points
// The majorRadius will be accurate +/- the majorRadiusTolerance
@property(nonatomic,readonly) CGFloat majorRadius NS_AVAILABLE_IOS(8_0);
@property(nonatomic,readonly) CGFloat majorRadiusTolerance NS_AVAILABLE_IOS(8_0);
@property(nullable,nonatomic,readonly,strong) UIWindow *window;
@property(nullable,nonatomic,readonly,strong) UIView *view;
@property(nullable,nonatomic,readonly,copy) NSArray <UIGestureRecognizer *> *gestureRecognizers NS_AVAILABLE_IOS(3_2);
// Get current location
- (CGPoint)locationInView:(nullable UIView *)view;
// To get on 1 The location of the touch points
- (CGPoint)previousLocationInView:(nullable UIView *)view;
// Force of the touch, where 1.0 represents the force of an average touch
@property(nonatomic,readonly) CGFloat force NS_AVAILABLE_IOS(9_0);
// Maximum possible force with this input mechanism
@property(nonatomic,readonly) CGFloat maximumPossibleForce NS_AVAILABLE_IOS(9_0);
@end
eg: make 1 view move with your finger
/**
* When a finger in view Called when moving up
*
* @param touches <#touches description#>
* @param event <#event description#>
*/
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
// To obtain UITouch object
UITouch *touch = [touches anyObject];
// Gets the position of the current point
CGPoint curP = [touch locationInView:self];
// To get on 1 The position of the point
CGPoint preP = [touch previousLocationInView:self];
// To calculate x The offset
CGFloat offsetX = curP.x - preP.x;
// To calculate y The offset
CGFloat offsetY = curP.y = preP.y;
// Modify the view The location of the
self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
}
This is based on the location information stored in the UITouch object.
Event generation and transmission:
When a touch event is generated, it is added to an event queue managed by UIApplication. UIApplication pulls the first event out of the queue and sends it to the processing of the application's main window. The main window finds the most appropriate view in the view hierarchy and calls the touches method to handle the touch event. The passing of the touch event is from the parent control to the child control. If the parent control cannot receive a touch event, then the child control cannot receive a touch event.
How do you find the most appropriate control to handle events? First determine if you can receive a touch event? Are the touch points on yourself? Walk through the child control from back to front, repeating the previous two steps, if there is no child control that meets the criteria, then handle it yourself.
The control USES the hitTest:withEvent: method to find the most suitable view, and pointInside to determine if the point is on the control or not on the method caller.
The underlying implementation of the hitTest method:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// Determines whether the current control can receive touch events
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
return nil;
}
// Determines if the touch point is on the current control
if ([self pointInside:point withEvent:event] == NO) {
return nil;
}
// Iterate over your child controls from back to front
NSInteger count = self.subviews.count;
for (NSInteger i = count - 1; i >= 0; i--) {
UIView *childView = self.subviews[i];
// Converts coordinates on the current control to coordinates on the child control
CGPoint childPoint = [self convertPoint:point toView:childView];
// Recursive calls hitTest Find the most suitable method view
UIView *fitView = [childView hitTest:childPoint withEvent:event];
if (fitView) {
return fitView;
}
}
// At the end of the cycle, nothing is better than yourself view , return to oneself
return self;
}
However, listening for touch events using the touches method has its drawbacks, such as customizing view, so iOS3.2 was followed by apple's launch of UIGestureRecognizer gesture recognition. UIGestureRecognizer is an abstract class whose subclasses can handle a specific gesture.
There are the following gestures:
// Click on the sign
// UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]initWithTarget:<#(nullable id)#> action:<#(nullable SEL)#>
// Long press gesture The default is to trigger twice
// UILongPressGestureRecognizer *longP = [UILongPressGestureRecognizer alloc]initWithTarget:<#(nullable id)#> action:<#(nullable SEL)#>
// Swept gently gestures The default direction is to the right
// UISwipeGestureRecognizer *swipe = [UISwipeGestureRecognizer alloc]initWithTarget:<#(nullable id)#> action:<#(nullable SEL)#>
// Rotation gestures
// UIRotationGestureRecognizer *rotation = [UIRotationGestureRecognizer alloc]initWithTarget:<#(nullable id)#> action:<#(nullable SEL)#>
// Kneading gestures
// UIPinchGestureRecognizer *pinch = [UIPinchGestureRecognizer alloc]initWithTarget:<#(nullable id)#> action:<#(nullable SEL)#>
// Drag and drop gesture
// UIPanGestureRecognizer *pan = [UIPanGestureRecognizer alloc]initWithTarget:<#(nullable id)#> action:<#(nullable SEL)#>
Practical application:
@interface ViewController ()<UIGestureRecognizerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpPinch];
[self setUpRotation];
[self setUpPan];
}
#pragma mark - Gesture proxy method
// Is it allowed to start triggering gestures
//- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
//{
// return NO;
//}
// If multiple gestures are allowed, the default is not to support multiple gestures
// return yes Supports multiple gestures
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
// Is it allowed to receive finger touch points
//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
// // Gets the current touch point
// CGPoint curP = [touch locationInView:self.imageView];
//
// if (curP.x < self.imageView.bounds.size.width * 0.5) {
// return NO;
// }else{
// return YES;
// }
//}
#pragma mark - Click on the sign
- (void)setUpTap
{
// Create a click gesture
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
tap.delegate = self;
[_imageView addGestureRecognizer:tap];
}
- (void)tap:(UITapGestureRecognizer *)tap
{
NSLog(@"%s",__func__);
}
#pragma mark - Long press gesture
// It will be triggered twice by default
- (void)setUpLongPress
{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[self.imageView addGestureRecognizer:longPress];
}
- (void)longPress:(UILongPressGestureRecognizer *)longPress
{
if (longPress.state == UIGestureRecognizerStateBegan) {
NSLog(@"%s",__func__);
}
}
#pragma mark - Swept gently
- (void)setUpSwipe
{
// The default direction of the swipe is to the right
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
swipe.direction = UISwipeGestureRecognizerDirectionUp;
[self.imageView addGestureRecognizer:swipe];
// If you want it later 1 Three controls support swiping in multiple directions, so you must create multiple swiping gestures, 1 A swipe gesture is only supported 1 A direction
// The default direction of the swipe is to the right
UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
[self.imageView addGestureRecognizer:swipeDown];
}
- (void)swipe
{
NSLog(@"%s",__func__);
}
#pragma mark - Rotation gestures
- (void)setUpRotation
{
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];
rotation.delegate = self;
[self.imageView addGestureRecognizer:rotation];
}
// The default is to pass the rotation Angle relative to the starting position
- (void)rotation:(UIRotationGestureRecognizer *)rotation
{
self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);
// reset
rotation.rotation = 0;
// Gets the Angle of rotation of the gesture
NSLog(@"%f",rotation.rotation);
}
#pragma mark - kneading
- (void)setUpPinch
{
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
pinch.delegate = self;
[self.imageView addGestureRecognizer:pinch];
}
- (void)pinch:(UIPinchGestureRecognizer *)pinch
{
self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);
// reset
pinch.scale = 1;
}
#pragma mark - Drag and drop
- (void)setUpPan
{
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self.imageView addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)pan
{
// Gets the touch point of a gesture
// CGPoint curP = [pan locationInView:self.imageView];
// Mobile view
// Get the movement of the gesture, also relative to the initial position
CGPoint transP = [pan translationInView:self.imageView];
self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, transP.x, transP.y);
// reset
[pan setTranslation:CGPointZero inView:self.imageView];
// NSLog(@"%@",NSStringFromCGPoint(curP));
}
@end
The above is iOS touch event and gesture related content introduction, hope to help you learn iOS programming.