UIPanGestureRecognizer 计算帧原点以保持相邻的子视图位置以进行图像裁剪
UIPanGestureRecognizer calculate frame origin to maintain adjacent subview position for image cropping
我有一个 cropView
,其中包含一个 cropBoxView
子视图,该子视图还包含四个正方形子视图,每个子视图上都有一个 UIPanGestureRecognizer
以启用裁剪区域的大小调整。
我想做的是改变框架大小但保持相邻方角的位置,这意味着我需要计算一个新的原点。我能够成功更改帧大小,但我不知道如何计算新原点。
目前,如果我平移视图的右下角,它会按我想要的方式工作(无需在下面的代码中调整原点),因为相邻的角是左上角,所以它的原点不会需要改变。
如果能提供任何帮助,我将不胜感激。
编辑:请参阅下面我的答案以获取结果和代码的示例 GIF
CGPoint translation = [recognizer translationInView:self.cropView];
CGRect recognizerFrame = self.cropView.cropBoxView.frame;
// Todo: calculate new origin based on adjacent crop corner
CGFloat testX = recognizerFrame.size.width += translation.x;
CGFloat testY = recognizerFrame.size.height += translation.y;
recognizerFrame.origin.x = recognizerFrame.origin.x - (recognizerFrame.size.width - testX);
recognizerFrame.origin.y = recognizerFrame.origin.y - (recognizerFrame.size.height - testY);
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height += translation.y;
[recognizer setTranslation:CGPointZero inView:self.cropView];
我自己解决了这个问题,它似乎工作得很好。
结果:
我所做的是子类化 UIPanGestureRecognizer
并定义一个枚举,用于调用手势的 shouldReceiveTouch
委托方法以确定在 cropBoxView 中触摸了哪个角。所以现在每个角都有一个单独的 UIPanGestureRecognizer
,我现在所有四个角都只有一个。
代码:
CropBoxCornerPanGestureRecognizer.h
#import <UIKit/UIGestureRecognizerSubclass.h>
#import <UIKit/UIPanGestureRecognizer.h>
typedef NS_ENUM(NSUInteger, corner)
{
TopLeftCorner = 1,
TopRightCorner,
BottomLeftCorner,
BottomRightCorner
};
@interface CropBoxCornerPanGestureRecognizer : UIPanGestureRecognizer
@property (nonatomic, assign) NSUInteger corner;
@end
CropBoxCornerPanGestureRecognizer.m
#import "CropBoxCornerPanGestureRecognizer.h"
@interface CropBoxCornerPanGestureRecognizer ()
@end
@implementation CropBoxCornerPanGestureRecognizer
@end
ViewController.h:
@interface ViewController : UIViewController <UIGestureRecognizerDelegate>
@end
ViewController.m:
@interface ViewController ()
@property (nonatomic, strong) CropBoxCornerPanGestureRecognizer *cropBoxCornerPanRecognizer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.cropBoxCornerPanRecognizer = [[CropBoxCornerPanGestureRecognizer alloc]init];
self.cropBoxCornerPanRecognizer.maximumNumberOfTouches = 1;
self.cropBoxCornerPanRecognizer.delaysTouchesBegan = NO;
self.cropBoxCornerPanRecognizer.delaysTouchesEnded = NO;
self.cropBoxCornerPanRecognizer.cancelsTouchesInView = NO;
[self.cropBoxCornerPanRecognizer addTarget:self action:@selector(panCropBoxCorner:)];
self.cropBoxCornerPanRecognizer.delegate = self;
self.cropView.cropBoxView addGestureRecognizer:self.cropBoxCornerPanRecognizer];
}
- (void)panCropBoxCorner:(CropBoxCornerPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:self.cropView];
CGRect recognizerFrame = self.cropView.cropBoxView.frame;
if (recognizer.corner == TopLeftCorner)
{
recognizerFrame.size.width -= translation.x;
recognizerFrame.size.height -= translation.y;
recognizerFrame.origin.x += translation.x;
recognizerFrame.origin.y += translation.y;
}
else if (recognizer.corner == TopRightCorner)
{
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height -= translation.y;
recognizerFrame.origin.y += translation.y;
}
else if (recognizer.corner == BottomLeftCorner)
{
recognizerFrame.size.width -= translation.x;
recognizerFrame.size.height += translation.y;
recognizerFrame.origin.x += translation.x;
}
else if (recognizer.corner == BottomRightCorner)
{
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height += translation.y;
}
CGFloat minFrameSize = 40.0;
CGFloat maxFrameWidth = self.cropView.frame.size.width;
CGFloat maxFrameHeight = self.cropView.frame.size.height;
if (recognizerFrame.size.width < minFrameSize)
{
recognizerFrame.size = CGSizeMake(minFrameSize, recognizerFrame.size.height);
}
if (recognizerFrame.size.height < minFrameSize)
{
recognizerFrame.size = CGSizeMake(recognizerFrame.size.width, minFrameSize);
}
if (recognizerFrame.size.width > maxFrameWidth)
{
recognizerFrame.size = CGSizeMake(maxFrameWidth, recognizerFrame.size.height);
}
if (recognizerFrame.size.height > maxFrameHeight)
{
recognizerFrame.size = CGSizeMake(recognizerFrame.size.width, maxFrameHeight);
}
[recognizer setTranslation:CGPointZero inView:self.cropView];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (gestureRecognizer == self.cropBoxCornerPanRecognizer)
{
CropBoxCornerPanGestureRecognizer *recognizer = (CropBoxCornerPanGestureRecognizer *)gestureRecognizer;
if (CGRectContainsPoint(self.cropView.cropBoxView.topLeftCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = TopLeftCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.topRightCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = TopRightCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.bottomLeftCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = BottomLeftCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.bottomRightCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = BottomRightCorner;
return YES;
}
return NO;
}
return YES;
}
我有一个 cropView
,其中包含一个 cropBoxView
子视图,该子视图还包含四个正方形子视图,每个子视图上都有一个 UIPanGestureRecognizer
以启用裁剪区域的大小调整。
我想做的是改变框架大小但保持相邻方角的位置,这意味着我需要计算一个新的原点。我能够成功更改帧大小,但我不知道如何计算新原点。
目前,如果我平移视图的右下角,它会按我想要的方式工作(无需在下面的代码中调整原点),因为相邻的角是左上角,所以它的原点不会需要改变。
如果能提供任何帮助,我将不胜感激。
编辑:请参阅下面我的答案以获取结果和代码的示例 GIF
CGPoint translation = [recognizer translationInView:self.cropView];
CGRect recognizerFrame = self.cropView.cropBoxView.frame;
// Todo: calculate new origin based on adjacent crop corner
CGFloat testX = recognizerFrame.size.width += translation.x;
CGFloat testY = recognizerFrame.size.height += translation.y;
recognizerFrame.origin.x = recognizerFrame.origin.x - (recognizerFrame.size.width - testX);
recognizerFrame.origin.y = recognizerFrame.origin.y - (recognizerFrame.size.height - testY);
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height += translation.y;
[recognizer setTranslation:CGPointZero inView:self.cropView];
我自己解决了这个问题,它似乎工作得很好。
结果:
我所做的是子类化 UIPanGestureRecognizer
并定义一个枚举,用于调用手势的 shouldReceiveTouch
委托方法以确定在 cropBoxView 中触摸了哪个角。所以现在每个角都有一个单独的 UIPanGestureRecognizer
,我现在所有四个角都只有一个。
代码:
CropBoxCornerPanGestureRecognizer.h
#import <UIKit/UIGestureRecognizerSubclass.h>
#import <UIKit/UIPanGestureRecognizer.h>
typedef NS_ENUM(NSUInteger, corner)
{
TopLeftCorner = 1,
TopRightCorner,
BottomLeftCorner,
BottomRightCorner
};
@interface CropBoxCornerPanGestureRecognizer : UIPanGestureRecognizer
@property (nonatomic, assign) NSUInteger corner;
@end
CropBoxCornerPanGestureRecognizer.m
#import "CropBoxCornerPanGestureRecognizer.h"
@interface CropBoxCornerPanGestureRecognizer ()
@end
@implementation CropBoxCornerPanGestureRecognizer
@end
ViewController.h:
@interface ViewController : UIViewController <UIGestureRecognizerDelegate>
@end
ViewController.m:
@interface ViewController ()
@property (nonatomic, strong) CropBoxCornerPanGestureRecognizer *cropBoxCornerPanRecognizer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.cropBoxCornerPanRecognizer = [[CropBoxCornerPanGestureRecognizer alloc]init];
self.cropBoxCornerPanRecognizer.maximumNumberOfTouches = 1;
self.cropBoxCornerPanRecognizer.delaysTouchesBegan = NO;
self.cropBoxCornerPanRecognizer.delaysTouchesEnded = NO;
self.cropBoxCornerPanRecognizer.cancelsTouchesInView = NO;
[self.cropBoxCornerPanRecognizer addTarget:self action:@selector(panCropBoxCorner:)];
self.cropBoxCornerPanRecognizer.delegate = self;
self.cropView.cropBoxView addGestureRecognizer:self.cropBoxCornerPanRecognizer];
}
- (void)panCropBoxCorner:(CropBoxCornerPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:self.cropView];
CGRect recognizerFrame = self.cropView.cropBoxView.frame;
if (recognizer.corner == TopLeftCorner)
{
recognizerFrame.size.width -= translation.x;
recognizerFrame.size.height -= translation.y;
recognizerFrame.origin.x += translation.x;
recognizerFrame.origin.y += translation.y;
}
else if (recognizer.corner == TopRightCorner)
{
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height -= translation.y;
recognizerFrame.origin.y += translation.y;
}
else if (recognizer.corner == BottomLeftCorner)
{
recognizerFrame.size.width -= translation.x;
recognizerFrame.size.height += translation.y;
recognizerFrame.origin.x += translation.x;
}
else if (recognizer.corner == BottomRightCorner)
{
recognizerFrame.size.width += translation.x;
recognizerFrame.size.height += translation.y;
}
CGFloat minFrameSize = 40.0;
CGFloat maxFrameWidth = self.cropView.frame.size.width;
CGFloat maxFrameHeight = self.cropView.frame.size.height;
if (recognizerFrame.size.width < minFrameSize)
{
recognizerFrame.size = CGSizeMake(minFrameSize, recognizerFrame.size.height);
}
if (recognizerFrame.size.height < minFrameSize)
{
recognizerFrame.size = CGSizeMake(recognizerFrame.size.width, minFrameSize);
}
if (recognizerFrame.size.width > maxFrameWidth)
{
recognizerFrame.size = CGSizeMake(maxFrameWidth, recognizerFrame.size.height);
}
if (recognizerFrame.size.height > maxFrameHeight)
{
recognizerFrame.size = CGSizeMake(recognizerFrame.size.width, maxFrameHeight);
}
[recognizer setTranslation:CGPointZero inView:self.cropView];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (gestureRecognizer == self.cropBoxCornerPanRecognizer)
{
CropBoxCornerPanGestureRecognizer *recognizer = (CropBoxCornerPanGestureRecognizer *)gestureRecognizer;
if (CGRectContainsPoint(self.cropView.cropBoxView.topLeftCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = TopLeftCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.topRightCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = TopRightCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.bottomLeftCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = BottomLeftCorner;
return YES;
}
if (CGRectContainsPoint(self.cropView.cropBoxView.bottomRightCorner.frame, [touch locationInView:self.cropView.cropBoxView]))
{
recognizer.corner = BottomRightCorner;
return YES;
}
return NO;
}
return YES;
}