我已经在我的应用程序中的UIImageView上实现了UIPinchGestureRecognizer,但无论我在哪里捏合图像,它似乎都放大到相同的位置。有谁知道如何让它放大到用户实际“捏”的位置?请参阅下面的代码。
ViewController.m
- (IBAction)scaleImage:(UIPinchGestureRecognizer *)recognizer {
recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
recognizer.scale = 1;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
{
BOOL shouldReceiveTouch = YES;
if (gestureRecognizer == tap) {
shouldReceiveTouch = (touch.view == featureImage);
}
return shouldReceiveTouch;
}
答案 0 :(得分:31)
缩放变换使原点(0,0)保持不变。因此,要缩放特定点周围的视图,必须首先将该点转换为原点,然后应用比例,然后转换回来。
- (IBAction)pinchGestureDidFire:(UIPinchGestureRecognizer *)pinch {
首先,我们得到视图被压缩。
UIView *pinchView = pinch.view;
要计算夹点的中心,我们需要视图边界的中点,所以我们也得到了界限:
CGRect bounds = pinchView.bounds;
中心是基于捏的触摸的质心,我们这样得到:
CGPoint pinchCenter = [pinch locationInView:pinchView];
但实际上我们需要相对于视图中心的夹点偏移,因为默认情况下视图的变换相对于视图的中心。 (您可以通过更改视图layer.anchorPoint
来更改此设置。)
pinchCenter.x -= CGRectGetMidX(bounds);
pinchCenter.y -= CGRectGetMidY(bounds);
现在我们可以更新视图的转换。首先,我们得到它当前的变换:
CGAffineTransform transform = pinchView.transform;
然后我们更新它以将夹点中心转换为原点:
transform = CGAffineTransformTranslate(transform, pinchCenter.x, pinchCenter.y);
现在我们可以应用比例:
CGFloat scale = pinch.scale;
transform = CGAffineTransformScale(transform, scale, scale);
然后我们将视图翻译回来:
transform = CGAffineTransformTranslate(transform, -pinchCenter.x, -pinchCenter.y);
现在我们可以使用修改后的转换更新视图:
pinchView.transform = transform;
最后,我们重置了手势识别器的比例,因为我们已经应用了当前比例:
pinch.scale = 1.0;
}
演示:
请注意,在模拟器中,您可以为捏合手势保留选项(alt)。按住shift(按住选项)可将两个触摸移动到一起。
以下是复制/粘贴的所有代码:
- (IBAction)pinchGestureDidFire:(UIPinchGestureRecognizer *)pinch {
UIView *pinchView = pinch.view;
CGRect bounds = pinchView.bounds;
CGPoint pinchCenter = [pinch locationInView:pinchView];
pinchCenter.x -= CGRectGetMidX(bounds);
pinchCenter.y -= CGRectGetMidY(bounds);
CGAffineTransform transform = pinchView.transform;
transform = CGAffineTransformTranslate(transform, pinchCenter.x, pinchCenter.y);
CGFloat scale = pinch.scale;
transform = CGAffineTransformScale(transform, scale, scale);
transform = CGAffineTransformTranslate(transform, -pinchCenter.x, -pinchCenter.y);
pinchView.transform = transform;
pinch.scale = 1.0;
}
答案 1 :(得分:8)
迅速实施抢劫答案:
@objc private func pinchHandler(gesture: UIPinchGestureRecognizer) {
if let view = gesture.view {
switch gesture.state {
case .changed:
let pinchCenter = CGPoint(x: gesture.location(in: view).x - view.bounds.midX,
y: gesture.location(in: view).y - view.bounds.midY)
let transform = view.transform.translatedBy(x: pinchCenter.x, y: pinchCenter.y)
.scaledBy(x: gesture.scale, y: gesture.scale)
.translatedBy(x: -pinchCenter.x, y: -pinchCenter.y)
view.transform = transform
gesture.scale = 1
case .ended:
// Nice animation to scale down when releasing the pinch.
// OPTIONAL
UIView.animate(withDuration: 0.2, animations: {
view.transform = CGAffineTransform.identity
})
default:
return
}
}
}
答案 2 :(得分:0)
你可以简单地添加一个scrollView,并在scrollView中添加一个imageView,如下所示,
![ImageView on top of scrollView][1]
图片上传存在一些问题,请在此link
查看图片然后,您可以创建scrollView和imageView的IBOutlet属性,并分别连接它。稍后,在viewDidAppear方法
中添加这些行_scrollView.maximumZoomScale = 10.0; //Maximum Zoom
_scrollView.minimumZoomScale = minimumScale; //Minimum Zoom
另外添加以下方法,
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return _imageView;
}
现在你可以获得你设置的放大/缩小效果和最大/最小缩放限制。较少的代码以及实现你的目标。
答案 3 :(得分:0)
Rob Mayoff(@robmayoff)的回答确实令人鼓舞,我希望我早点找到它。但是我实际上是通过更改锚点而不是使用转换转换来解决的。实际上,它具有相同的结果。
我还没有在SO上看到这种解决方案(但...),并认为这是个好地方。
相对于视图层锚点转换工作。但是,如果视图已转换,则不能仅将位置点设置为收缩中心点。因此,这是一种设置图层锚点并正确转换位置点的方法:
// change the anchor point for the view layer
- (void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view {
// sanity check - x and y MUST be between 0 and 1
if (anchorPoint.x < 0 || anchorPoint.x > 1 ||
anchorPoint.y < 0 || anchorPoint.y > 1) {
return;
}
CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x,
view.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x,
view.bounds.size.height * view.layer.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);
CGPoint position = view.layer.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
view.layer.position = position;
view.layer.anchorPoint = anchorPoint;
}
这是handlePinch
方法,它使用setAnchorPoint
方法将图层锚点设置为收缩接触点的中心点:
- (void)handlePinch:(UIPinchGestureRecognizer *)recognizer {
// make these static so they can be used across gesture states
static CGAffineTransform initialTransform;
static CGPoint initialAnchor;
if (recognizer.state == UIGestureRecognizerStateBegan) {
// save these for later states
initialTransform = recognizer.view.transform;
initialAnchor = recognizer.view.layer.anchorPoint;
// get the center point of the pinch
CGPoint touch = [recognizer locationInView:recognizer.view];
// anchor point is relative to the view bounds: 0 ... up to 1.0, for both x and y
CGFloat anchorX = touch.x / recognizer.view.bounds.size.width;
CGFloat anchorY = touch.y / recognizer.view.bounds.size.height;
// set the layer anchor point AND position, to where the view was initially pinched
[self setAnchorPoint:CGPointMake(anchorX,anchorY) forView:recognizer.view];
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
// perform the pinch zoom
recognizer.view.transform = CGAffineTransformScale(initialTransform,recognizer.scale,recognizer.scale);
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
// reset the scale when it's done
recognizer.scale = 1;
// restore the original anchor point
[self setAnchorPoint:initialAnchor forView:recognizer.view];
}
}
答案 4 :(得分:-1)
ViewController.h
@property (strong, nonatomic) IBOutlet UIImageView *img;
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchDetected:)];
[_img addGestureRecognizer:pinchRecognizer];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)pinchDetected:(UIPinchGestureRecognizer *)pinchRecognizer
{
CGFloat scale = pinchRecognizer.scale;
_img.transform = CGAffineTransformScale(self.img.transform, scale, scale);
pinchRecognizer.scale = 1.0;
}