UIPinchGestureRecognizer中捏放大的最大/最小缩放比例 - iPhone iOS
如何才能将UIPinchGestureRecognizer的缩放比例限制为最小和最大值?下面的缩放属性似乎是相对于最后一个已知的缩放比例(来自上一个状态的增量),我无法弄清楚如何设置对缩放对象的大小/高度的限制。UIPinchGestureRecognizer中捏放大的最大/最小缩放比例 - iPhone iOS
-(void)scale:(id)sender {
[self.view bringSubviewToFront:[(UIPinchGestureRecognizer*)sender view]];
if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
lastScale = 1.0;
return;
}
CGFloat pinchscale = [(UIPinchGestureRecognizer*)sender scale];
CGFloat scale = 1.0 - (lastScale - pinchscale);
CGAffineTransform currentTransform = [(UIPinchGestureRecognizer*)sender view].transform;
CGAffineTransform holderTransform = holderView.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[[(UIPinchGestureRecognizer*)sender view] setTransform:newTransform];
lastScale = [(UIPinchGestureRecognizer*)sender scale];
}
没有办法限制UIPinchGestureRecognizer
上的比例。要限制在你的代码的高度,你应该能够做这样的事情:
CGFloat scale = 1.0 - (lastScale - pinchscale);
CGRect bounds = [(UIPinchGestureRecognizer*)sender view].bounds;
scale = MIN(scale, maximumHeight/CGRectGetHeight(bounds));
scale = MAX(scale, minimumHeight/CGRectGetHeight(bounds));
要在最后两行限制宽度,改变“高”到“宽”。
你能使用滚动视图?然后,您可以使用scrollView.minimumZoomScale和scrollView.maximumZoomScale
嗯,有趣的...将作为解决问题的替代方法。 – VinnyD 2011-03-01 17:14:20
下面是我使用Anomie的答案作为出发点后想到的解决方案。
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer {
if([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
// Reset the last scale, necessary if there are multiple objects with different scales
lastScale = [gestureRecognizer scale];
}
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ||
[gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGFloat currentScale = [[[gestureRecognizer view].layer valueForKeyPath:@"transform.scale"] floatValue];
// Constants to adjust the max/min values of zoom
const CGFloat kMaxScale = 2.0;
const CGFloat kMinScale = 1.0;
CGFloat newScale = 1 - (lastScale - [gestureRecognizer scale]);
newScale = MIN(newScale, kMaxScale/currentScale);
newScale = MAX(newScale, kMinScale/currentScale);
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], newScale, newScale);
[gestureRecognizer view].transform = transform;
lastScale = [gestureRecognizer scale]; // Store the previous scale factor for the next pinch gesture call
}
}
伟大的解决方案!我一直在寻找这个永远!为什么它不在这个问题的顶部!?谢谢 – tentmaking 2013-05-31 00:10:35
谢谢! - 谢谢 ! - 谢谢! 。 。 。 。:D – 2013-08-20 14:05:27
在设置了gestureRecognizer视图的变换之后添加下面这行:[recognitionzer setScale:1.0]; – morph85 2013-11-13 10:07:59
我花了一些信息,从保罗绍尔特和Anoime的回答收集,并补充说,现有的类别我已经为UIViewController中允许进行任何的UIView拖动的,到现在为止使其pinchable用手势和变换。
注意:这使您可拖动/可捏合的视图的标签属性变脏。所以如果你需要标签来替代别的东西,你可以考虑把这个值放在这个技术使用的NSMutableDictionary中。这可作为[自dictForView:theView]
在项目实施:
可以使视图控制器内的任意子视图“视图”拖动或pinchable(或两者) 地方单行的代码在你的viewDidLoad中(例如:)
[self makeView:mySubView draggable:YES pinchable:YES minPinchScale:0.75 maxPinchScale:1.0];
关闭它在viewDidUnload(版本guestures &字典):
[self makeView:mySubView draggable:NO pinchable:NO minPinchScale:1.0 maxPinchScale:1.0];
DragAndPinchScale.h文件
#import <UIKit/UIKit.h>
@interface UIViewController (DragAndPinchScale)
-(void) makeView:(UIView*)aView
draggable:(BOOL)draggable
pinchable:(BOOL)pinchable
minPinchScale:(CGFloat)minPinchScale
maxPinchScale:(CGFloat)maxPinchScale;
-(NSMutableDictionary *) dictForView:(UIView *)theView;
-(NSMutableDictionary *) dictForViewGuestures:(UIGestureRecognizer *)guesture;
@end
DragAndPinchScale.m文件
#import "DragAndPinchScale.h"
@implementation UIViewController (DragAndPinchScale)
-(NSMutableDictionary *) dictForView:(UIView *)theView{
NSMutableDictionary *dict = (NSMutableDictionary*) (void*) theView.tag;
if (!dict) {
dict = [[NSMutableDictionary dictionary ] retain];
theView.tag = (NSInteger) (void *) dict;
}
return dict;
}
-(NSMutableDictionary *) dictForViewGuestures:(UIGestureRecognizer *)guesture {
return [self dictForView:guesture.view];
}
- (IBAction)fingersDidPinchInPinchableView:(UIPinchGestureRecognizer *)fingers {
NSMutableDictionary *dict = [self dictForViewGuestures:fingers];
UIView *viewToZoom = fingers.view;
CGFloat lastScale;
if([fingers state] == UIGestureRecognizerStateBegan) {
// Reset the last scale, necessary if there are multiple objects with different scales
lastScale = [fingers scale];
} else {
lastScale = [[dict objectForKey:@"lastScale"] floatValue];
}
if ([fingers state] == UIGestureRecognizerStateBegan ||
[fingers state] == UIGestureRecognizerStateChanged) {
CGFloat currentScale = [[[fingers view].layer valueForKeyPath:@"transform.scale"] floatValue];
// limits to adjust the max/min values of zoom
CGFloat maxScale = [[dict objectForKey:@"maxScale"] floatValue];
CGFloat minScale = [[dict objectForKey:@"minScale"] floatValue];
CGFloat newScale = 1 - (lastScale - [fingers scale]);
newScale = MIN(newScale, maxScale/currentScale);
newScale = MAX(newScale, minScale/currentScale);
CGAffineTransform transform = CGAffineTransformScale([[fingers view] transform], newScale, newScale);
viewToZoom.transform = transform;
lastScale = [fingers scale]; // Store the previous scale factor for the next pinch gesture call
}
[dict setObject:[NSNumber numberWithFloat:lastScale]
forKey:@"lastScale"];
}
- (void)fingerDidMoveInDraggableView:(UIPanGestureRecognizer *)finger {
NSMutableDictionary *dict = [self dictForViewGuestures:finger];
UIView *viewToDrag = finger.view;
if (finger.state == UIGestureRecognizerStateBegan) {
[dict setObject:[NSValue valueWithCGPoint:viewToDrag.frame.origin]
forKey:@"startDragOffset"];
[dict setObject:[NSValue valueWithCGPoint:[finger locationInView:self.view]]
forKey:@"startDragLocation"];
}
else if (finger.state == UIGestureRecognizerStateChanged) {
NSMutableDictionary *dict = (NSMutableDictionary*) (void*) viewToDrag.tag;
CGPoint stopLocation = [finger locationInView:self.view];
CGPoint startDragLocation = [[dict valueForKey:@"startDragLocation"] CGPointValue];
CGPoint startDragOffset = [[dict valueForKey:@"startDragOffset"] CGPointValue];
CGFloat dx = stopLocation.x - startDragLocation.x;
CGFloat dy = stopLocation.y - startDragLocation.y;
// CGFloat distance = sqrt(dx*dx + dy*dy);
CGRect dragFrame = viewToDrag.frame;
CGSize selfViewSize = self.view.frame.size;
if (!UIDeviceOrientationIsPortrait(self.interfaceOrientation)) {
selfViewSize = CGSizeMake(selfViewSize.height,selfViewSize.width);
}
selfViewSize.width -= dragFrame.size.width;
selfViewSize.height -= dragFrame.size.height;
dragFrame.origin.x = MIN(selfViewSize.width, MAX(0,startDragOffset.x+dx));
dragFrame.origin.y = MIN(selfViewSize.height,MAX(0,startDragOffset.y+dy));
viewToDrag.frame = dragFrame;
}
else if (finger.state == UIGestureRecognizerStateEnded) {
[dict removeObjectForKey:@"startDragLocation"];
[dict removeObjectForKey:@"startDragOffset"];
}
}
-(void) makeView:(UIView*)aView
draggable:(BOOL)draggable
pinchable:(BOOL)pinchable
minPinchScale:(CGFloat)minPinchScale
maxPinchScale:(CGFloat)maxPinchScale{
NSMutableDictionary *dict = (NSMutableDictionary*) (void*) aView.tag;
if (!(pinchable || draggable)) {
if (dict){
[dict release];
aView.tag = 0;
}
return;
}
if (dict) {
UIPanGestureRecognizer *pan =[dict objectForKey:@"UIPanGestureRecognizer"];
if(pan){
if ([aView.gestureRecognizers indexOfObject:pan]!=NSNotFound) {
[aView removeGestureRecognizer:pan];
}
[dict removeObjectForKey:@"UIPanGestureRecognizer"];
}
UIPinchGestureRecognizer *pinch =[dict objectForKey:@"UIPinchGestureRecognizer"];
if(pinch){
if ([aView.gestureRecognizers indexOfObject:pinch]!=NSNotFound) {
[aView removeGestureRecognizer:pinch];
}
[dict removeObjectForKey:@"UIPinchGestureRecognizer"];
}
[dict removeObjectForKey:@"startDragLocation"];
[dict removeObjectForKey:@"startDragOffset"];
[dict removeObjectForKey:@"lastScale"];
[dict removeObjectForKey:@"minScale"];
[dict removeObjectForKey:@"maxScale"];
}
if (draggable) {
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(fingerDidMoveInDraggableView:)];
pan.minimumNumberOfTouches = 1;
pan.maximumNumberOfTouches = 1;
[aView addGestureRecognizer:pan];
[pan release];
dict = [self dictForViewGuestures:pan];
[dict setObject:pan forKey:@"UIPanGestureRecognizer"];
}
if (pinchable) {
CGAffineTransform initialTramsform = CGAffineTransformMakeScale(1.0, 1.0);
aView.transform = initialTramsform;
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(fingersDidPinchInPinchableView:)];
[aView addGestureRecognizer:pinch];
[pinch release];
dict = [self dictForViewGuestures:pinch];
[dict setObject:pinch forKey:@"UIPinchGestureRecognizer"];
[dict setObject:[NSNumber numberWithFloat:minPinchScale] forKey:@"minScale"];
[dict setObject:[NSNumber numberWithFloat:maxPinchScale] forKey:@"maxScale"];
}
}
@end
感谢它与我的代码工作正常。 我长期面对这个问题,但您的上述代码帮助我解决了这个问题。 再次感谢 – Prashant 2012-02-18 05:41:19
谢谢,真正有用的代码片段上面夹紧到最小和最大规模。
我发现,当我第一次翻转使用视图:
CGAffineTransformScale(gestureRecognizer.view.transform, -1.0, 1.0);
它将缩放视图时会闪烁。
让我知道你在想什么,但对我来说,解决方案是更新上面的代码示例,如果视图已经被翻转(旗通过属性设置),然后倒置刻度值:
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged)
{
CGFloat currentScale = [[[gestureRecognizer view].layer valueForKeyPath:@"transform.scale"] floatValue];
if(self.isFlipped) // (inverting)
{
currentScale *= -1;
}
CGFloat newScale = 1 - (self.lastScale - [gestureRecognizer scale]);
newScale = MIN(newScale, self.maximumScaleFactor/currentScale);
newScale = MAX(newScale, self.minimumScaleFactor/currentScale);
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], newScale, newScale);
gestureRecognizer.view.transform = transform;
self.lastScale = [gestureRecognizer scale]; // Store the previous scale factor for the next pinch gesture call
其他这里提到的方法并不适用于我,但从以前的答案和(在我看来)简化了一些事情,我已经得到了这个为我工作。 是在viewDidLoad
中设置为1.0的伊娃。
-(void)zoomScale:(UIPinchGestureRecognizer *)recognizer
{
if([recognizer state] == UIGestureRecognizerStateEnded) {
// Reset last scale
lastScale = 1.0;
return;
}
if ([recognizer state] == UIGestureRecognizerStateBegan ||
[recognizer state] == UIGestureRecognizerStateChanged) {
CGFloat pinchscale = [recognizer scale];
CGFloat scaleDiff = pinchscale - lastScale;
if (scaleDiff < 0)
scaleDiff *= 2; // speed up zoom-out
else
scaleDiff *= 0.7; // slow down zoom-in
effectiveScale += scaleDiff;
// Limit scale between 1 and 2
effectiveScale = effectiveScale < 1 ? 1 : effectiveScale;
effectiveScale = effectiveScale > 2 ? 2 : effectiveScale;
// Handle transform in separate method using new effectiveScale
[self makeAndApplyAffineTransform];
lastScale = pinchscale;
}
}
这是一种处理手势识别器的“scale”属性中固有的非线性的复杂方式,它也没有正确处理它,它只是通过0.7来进行缩放。看到我的答案更好的方法:) – damian 2014-01-20 10:39:51
与大多数其他的答案的问题是,他们正试图处理规模为线性值,而实际上它是非线性的,由于道路UIPinchGestureRecognizer
计算其规模属性基于触摸距离。当没有考虑到这一点时,用户必须使用或多或少的夹点距离来“撤消”前一个捏合手势所应用的缩放。
考虑:假设transform.scale
= 1.0
,我6厘米除了在屏幕上把我的手指,然后向内捏3厘米分开 - 生成的gestureRecognizer.scale
是0.5
,并0.5-1.0
为-0.5
,所以transform.scale
将成为1.0+(-0.5)
= 0.5
。现在,我抬起我的手指,将它们放回距离3厘米,并向外捏6厘米。由此产生的gestureRecognizer.scale
将是2.0
,并且2.0-1.0
是1.0
,因此transform.scale
将变为0.5+1.0
= 1.5
。不是我想要发生的事情。
解决的办法是计算三角箍缩比例作为其先前值的比例。我将手指放在距离6厘米的地方,并向内捏至3厘米,所以gestureRecognizer.scale
是0.5
。 0.5/1.0
是0.5
,所以我的新transform.scale
是1.0*0.5
= 0.5
。接下来,我将手指放下3厘米,然后向外掐6厘米。 gestureRecognizer.scale
然后是2.0
和2.0/1.0
是2.0
,所以我的新transform.scale
是0.5*2.0
= 1.0
,这正是我想要发生的。
这是代码:
在-(void)viewDidLoad
:
self.zoomGestureCurrentZoom = 1.0f;
在-(void)onZoomGesture:(UIPinchGestureRecognizer*)gestureRecognizer
:
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
self.zoomGestureLastScale = gestureRecognizer.scale;
}
else if (gestureRecognizer.state == UIGestureRecognizerStateChanged)
{
// we have to jump through some hoops to clamp the scale in a way that makes the UX intuitive
float scaleDeltaFactor = gestureRecognizer.scale/self.zoomGestureLastScale;
float currentZoom = self.zoomGestureCurrentZoom;
float newZoom = currentZoom * scaleDeltaFactor;
// clamp
float kMaxZoom = 4.0f;
float kMinZoom = 0.5f;
newZoom = MAX(kMinZoom,MIN(newZoom,kMaxZoom));
self.view.transform = CGAffineTransformScale([[gestureRecognizer view] transform], newZoom, newZoom);
// store for next time
self.zoomGestureCurrentZoom = newZoom;
self.zoomGestureLastScale = gestureRecognizer.scale;
}
这不适合我当我将它设置为一个特定的视图,gestureRecognizer.view 我遇到了“速度”不同的多个pinches问题,我想这就是你所得到的。 – 2014-06-14 20:59:05
@PaulSolt嗯,是的..我猜我在哪里'[[gestureRecognizer视图]转换]'也许可以通过'CGAffineTransformIdentity'?我认为在我基于此的代码中,'self.view'应该与'gestureRecognizer.view'不同。不记得对不起:/ – damian 2014-06-16 09:30:19
- (void)handlePinch:(UIPinchGestureRecognizer *)recognizer{
//recognizer.scale=1;
CGFloat pinchScale = recognizer.scale;
pinchScale = round(pinchScale * 1000)/1000.0;
NSLog(@"%lf",pinchScale);
if (pinchScale < 1)
{
currentLabel.font = [UIFont fontWithName:currentLabel.font.fontName size:
(currentLabel.font.pointSize - pinchScale)];
recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
[currentLabel sizeToFit];
recognizer.scale=1;
}
else
{
currentLabel.font = [UIFont fontWithName:currentLabel.font.fontName size:(currentLabel.font.pointSize + pinchScale)];
recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
[currentLabel sizeToFit];
recognizer.scale=1;
}
//currentLabel.adjustsFontSizeToFitWidth = YES;
// [currentLabel sizeToFit];
NSLog(@"Font :%@",label.font);
}
你应该更新你的格式。阅读并不容易。 – 2014-05-28 15:11:46
ohhhh多数民众赞成在非常好它的真正工作thx ...! 但我想改变我的标签框架在这种方法我尝试它,但它不是完美的水平和垂直捏完成它改变它的高度和宽度,所以你可以帮我... THX ...先生Arvind库马尔。 。:) – 2015-04-16 12:22:07
- (void)pinchToZoom:(UIPinchGestureRecognizer*)gesture
{
switch (gesture.state)
{
case UIGestureRecognizerStateBegan:
{
lastScale = gesture.scale;
}break;
case UIGestureRecognizerStateChanged:
{
const CGFloat zoomSensitivity = 5;
const CGFloat zoomMin = 1;
const CGFloat zoomMax = 16;
CGFloat objectScale = gesture.view.contentScaleFactor;
CGFloat zoomDiff = lastScale - gesture.scale;
CGFloat zoomDirty = objectScale - zoomDiff * zoomSensivity;
CGFloat zoomTo = fmaxf(zoomMin, fminf(zoomDirty, zoomMax));
// step round if needed (neutralize elusive changes)
zoomTo = (NSInteger)(zoomTo * 10) * 0.1;
if (objectScale != zoomTo)
gesture.view.contentScaleFactor = zoomTo;
lastScale = gesture.scale;
}break;
default:
break;
}
}
看看这个样本上的双指缩放的http:// cocoabugs .blogspot.com/2011/03 /捏变焦使用,uipinchg estmmrecogniz.html – 2011-03-10 02:46:32