引言
- iOS 小技能:Responder Chain(响应者链)【上篇】https://kunnan.blog.csdn.net/article/details/122809496
- iOS 小技能:Responder Chain(响应者链)【下篇】https://kunnan.blog.csdn.net/article/details/122811653
- 手势识别器
- 抽屉效果的实现
I 手势识别器
为了完成手势识别,必须借助于手势识别器UIGestureRecognizer。利用UIGestureRecognizer,能轻松识别用户在某个view上面做的一些常见手势。
1.1 手势识别的状态
这里写图片描述
代码语言:javascript复制typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
UIGestureRecognizerStatePossible, // the recognizer has not yet recognized its gesture, but may be evaluating touch events. this is the default state没有触摸事件发生,所有手势识别的默认状态
UIGestureRecognizerStateBegan, // the recognizer has received touches recognized as the gesture. the action method will be called at the next turn of the run loop // 一个手势已经开始但尚未改变或者完成时
UIGestureRecognizerStateChanged, // the recognizer has received touches recognized as a change to the gesture. the action method will be called at the next turn of the run loop // 手势状态改变
UIGestureRecognizerStateEnded, // the recognizer has received touches recognized as the end of the gesture. the action method will be called at the next turn of the run loop and the recognizer will be reset to UIGestureRecognizerStatePossible // 手势完成
UIGestureRecognizerStateCancelled, // the recognizer has received touches resulting in the cancellation of the gesture. the action method will be called at the next turn of the run loop. the recognizer will be reset to UIGestureRecognizerStatePossible // 手势取消,恢复至Possible状态
UIGestureRecognizerStateFailed, // the recognizer has received a touch sequence that can not be recognized as the gesture. the action method will not be called and the recognizer will be reset to UIGestureRecognizerStatePossible // 手势失败,恢复至Possible状态
// Discrete Gestures – gesture recognizers that recognize a discrete event but do not report changes (for example, a tap) do not transition through the Began and Changed states and can not fail or be cancelled //
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded // the recognizer has received touches recognized as the gesture. the action method will be called at the next turn of the run loop and the recognizer will be reset to UIGestureRecognizerStatePossible 识别到手势识别
};
1、UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势 子类:
代码语言:javascript复制UITapGestureRecognizer(敲击)
UIPinchGestureRecognizer(捏合,用于缩放)
UIPanGestureRecognizer(拖拽)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)
2、 UITapGestureRecognizer
1.2 手势识别器的使用步骤
代码语言:javascript复制每一个手势识别器的用法都差不多,比如UITapGestureRecognizer的使用步骤:
//创建手势识别器对象
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
//设置手势识别器对象的具体属性
// 连续敲击2次
tap.numberOfTapsRequired = 2;
// 需要2根手指一起敲击
tap.numberOfTouchesRequired = 2;
//添加手势识别器到对应的view上
[self.iconView addGestureRecognizer:tap];
//监听手势的触发
[tap addTarget:self action:@selector(tapIconView:)];
1.3 手势识别器的使用
代码语言:javascript复制//
#import "ViewController.h"
@interface ViewController () <UIGestureRecognizerDelegate>
@property (strong, nonatomic) IBOutlet UIView *ImageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// [self adTap];
// [self addLongPress];
// [self addSwipe];
// [self addRotation];
// [self addPinch];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
[self.ImageView addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)pan{
NSLog(@"%s",__func__);
CGPoint translation = [pan translationInView:self.ImageView];
[self.ImageView setTransform:CGAffineTransformTranslate(self.ImageView.transform, translation.x, translation.y)];//相对于上一次的位置移动
//复位
[pan setTranslation:CGPointZero inView:self.ImageView];
}
- (void) addPinch{
[self addRotation];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
[pinch setDelegate:self];
[self.ImageView addGestureRecognizer:pinch];
}
- (void)pinch:(UIPinchGestureRecognizer *)pinch{
[self.ImageView setTransform:CGAffineTransformScale(self.ImageView.transform, pinch.scale, pinch.scale)];
//复位
pinch.scale = 1;
}
- (void)addRotation{
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)];
[rotation setDelegate:self];
[self.ImageView addGestureRecognizer:rotation];
}
#pragma mark - rolation
- (void) rotation:(UIRotationGestureRecognizer *)rotation{
NSLog(@"%s",__func__);
// [self.ImageView setTransform:CGAffineTransformMakeRotation(rotation.rotation)];
[self.ImageView setTransform:CGAffineTransformRotate(self.ImageView.transform, rotation.rotation)];//基于之前的transform进行形变
rotation.rotation=0;//进行复位
}
- (void) addSwipe{
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
/**
UISwipeGestureRecognizerDirectionRight = 1 << 0,
UISwipeGestureRecognizerDirectionLeft = 1 << 1,
UISwipeGestureRecognizerDirectionUp = 1 << 2,
UISwipeGestureRecognizerDirectionDown = 1 << 3
*/
[swipe setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.ImageView addGestureRecognizer:swipe];
}
- (void)swipe:(UISwipeGestureRecognizer *)swipe{
NSLog(@"%s",__func__);
}
- (void) addLongPress{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
[self.ImageView addGestureRecognizer:longPress];
}
- (void)longPress:(UILongPressGestureRecognizer *)longPress{
if (longPress.state == UIGestureRecognizerStateEnded) {
NSLog(@"%s",__func__);
}
}
- (void) adTap{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
// [tap setNumberOfTapsRequired:2];
// [tap setNumberOfTouchesRequired:2];
//手势识别器的代理属性设置
[tap setDelegate:self];
[self.ImageView addGestureRecognizer:tap];
}
- (void)tap:(UITapGestureRecognizer *)tap {
NSLog(@"%s",__func__);
}
#pragma mark - UIGestureRecognizerDelegate
#pragma mark - 同时支持多个手势识别器
// called when the recognition of one of gestureRecognizer or otherGestureRecognizer would be blocked by the other
// return YES to allow both to recognize simultaneously. the default implementation returns NO (by default no two gestures can be recognized simultaneously)
//
// note: returning YES is guaranteed to allow simultaneous recognition. returning NO is not guaranteed to prevent simultaneous recognition, as the other gesture's delegate may return YES
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;//同时支持多个手势
}
// called before touchesBegan:withEvent: is called on the gesture recognizer for a new touch. return NO to prevent the gesture recognizer from seeing this touch
#if 0
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
CGPoint currentFrame = [touch locationInView:self.ImageView];
if (currentFrame.x< 0.5*(CGRectGetWidth(self.ImageView.frame))) {
return NO;
}
return YES;
}
#endif
@end
II 抽屉效果
抽屉效果的例子
https://github.com/zhangkn/HSDrawViewController
2.1 抽屉效果
代码语言:javascript复制#pragma mark - touches
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//就算偏移量
UITouch *touch = [touches anyObject];
CGPoint current = [touch locationInView:self.mainView];
CGPoint pre = [touch previousLocationInView:self.mainView];
//x的偏移量
CGFloat offsetX = current.x - pre.x;
[self.mainView setFrame:[self getCurrentFrameWithOffsetX:offsetX]];
}
/*
根据x的便宜量计算frame
*/
- (CGRect)getCurrentFrameWithOffsetX:(CGFloat) offsetX{
//y的偏移量
CGFloat offsetY;
if (self.mainView.frame.origin.x<0) {
offsetY = HSMaxY*offsetX/HSScreenWidth*-1;//保证正数,即保证currentHeight 小于screenHeight
}else{
offsetY = HSMaxY*offsetX/HSScreenWidth;//保证正数,即保证currentHeight 小于screenHeight
}
CGFloat currentHeight = HSScreenHeight-2*offsetY;//当前的高度
CGFloat scale =(currentHeight)/HSScreenHeight;//比例
CGRect mainFrame = self.mainView.frame;
mainFrame.origin.x = offsetX;
mainFrame.size.height *= scale;
mainFrame.size.width *= scale;
mainFrame.origin.y = (HSScreenHeight- mainFrame.size.height)*0.5;
return mainFrame;
}
2.2 抽屉效果的定位和复位
- 定位、复位
/*
抽屉效果的定位
当minx >0.5HSScreenWidth 定位到右侧
当Max <0.5HSScreenWidth 定位到左侧
*/
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1、复位
if (self.isDraging == NO && self.mainView.frame.origin.x != 0) {
[UIView animateWithDuration:0.25 animations:^{
//复位
[self.mainView setFrame:self.view.bounds];
}];
}
//2定位
CGFloat target = 0;
if (self.mainView.frame.origin.x >0.5*HSScreenWidth) {
//定位到右侧
target = HSRightTarget;
}else if (CGRectGetMaxX(self.mainView.frame) < 0.5*HSScreenWidth ){
target = HSLeftTarget;
}
[UIView animateWithDuration:0.25 animations:^{
//复位、定位
if (target) {//不为0 才需要定位
CGFloat offsetX = target - self.mainView.frame.origin.x;
//需要定位
[self.mainView setFrame:[self getCurrentFrameWithOffsetX:offsetX]];
}else{
// 复位
[self.mainView setFrame:self.view.bounds];
}
}];
[self setIsDraging:NO];//停止拖动
}
2.3 完整demo
https://download.csdn.net/download/u011018979/79582238