当我放大屏幕时,我遇到了uipangesturerecognizer的问题。
我的应用程序有一个带uiview的uiviewcontroller。
在这个视图中,我有一个几乎占整个屏幕边界一半的calayer。
这个calayer有几个子图层,用户可以拖动(uipangesture),添加(uitapgesture)和删除(doubletapgesture)。为了更准确地拖动,我添加了一个uipinchgesture方法来放大和缩小。
此时一切正常,除非我放大并尝试移动(pangesture)子层。有时工作但通常不工作(没有放大总能正常工作)。
我不知道我的代码中是否有问题,或者可能不是这样做的。有什么我想念的吗?
我在sdk 4.2下。
这些是我的代码:
- (id)initWithFrame:(CGRect)frame { [super initWithFrame:frame]; (…) perfil = [[CALayer alloc] init]; //the calayer of the uiview [perfil setBounds:CGRectMake(0, 0, wide, heigth/2)]; [[self layer] addSublayer:perfil]; //I add the sublayers to the "peril" layer when the user touch an "edit button" and that works fine //UIGsture Recognizers UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapFrom:)]; UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapFrom:)]; UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchFrom:)]; UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)]; [panGestureRecognizer setMinimumNumberOfTouches:1]; [panGestureRecognizer setMaximumNumberOfTouches:1]; [singleTapRecognizer setNumberOfTapsRequired:1]; [singleTapRecognizer setCancelsTouchesInView:NO]; [doubleTapRecognizer setNumberOfTapsRequired:2]; [self addGestureRecognizer:singleTapRecognizer]; [self addGestureRecognizer:doubleTapRecognizer]; [self addGestureRecognizer:pinchGestureRecognizer]; [self addGestureRecognizer:panGestureRecognizer]; [singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer]; singleTapRecognizer.delegate = self; doubleTapRecognizer.delegate = self; pinchGestureRecognizer.delegate = self; panGestureRecognizer.delegate = self; //Some other different stuff here }
- (void) handlePanFrom: (id)sender { CGPoint point = [(UIPanGestureRecognizer*)sender locationInView:self]; boxLayer = [[self perfil] hitTest:point]; [self becomeFirstResponder]; if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) { numberOfSublayer = 1000; //declared as a int in UIView.h for (CALayer *elements in [perfil sublayers]) { if([boxLayer isEqual:elements]) { numberOfSublayer = [[perfil sublayers] indexOfObject:elements]; break; } } } (…) //Some more operations once I found the sublayer }
- (void) handlePinchFrom: (id)sender { if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) { lastScale = 1.0; return; } if ([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan || [(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged) { CGFloat currentScale = [[[sender view].layer valueForKeyPath:@"transform.scale"] floatValue]; const CGFloat kMaxScale = 4.0; const CGFloat kMinScale = 1.0; CGFloat newScale = 1 - (lastScale - [(UIPinchGestureRecognizer*)sender scale]); newScale = MIN(newScale, kMaxScale / currentScale); newScale = MAX(newScale, kMinScale / currentScale); CGAffineTransform transform = CGAffineTransformScale([[sender view] transform], newScale, newScale); [sender view].transform = transform; if ([perfil sublayers]) { for (CALayer *elements in [perfil sublayers]) //Here I try to adjust the zoom to the sublayers { //Here is one first approach //CGAffineTransform transformELS = CGAffineTransformScale([elements affineTransform], 7/(newScale+6), 7/(newScale+6)); //[elements setAffineTransform:transformELS]; //Here is a second approach [elements setBounds:CGRectMake(0, 0, elements.bounds.size.width*7/(newScale+6), elements.bounds.size.height*7/(newScale+6))]; } } lastScale = [(UIPinchGestureRecognizer*)sender scale]; (…) //Some other different stuff here }
非常感谢。
答案 0 :(得分:1)
最后我找到了问题的答案。这篇文章解释了完全相同的问题,它的解决方案对我来说非常有用 UIPanGestureRecognizer starting point is off。感谢。
答案 1 :(得分:0)
如果没有看到sublayer hittest代码真的很难说,但是在重新缩放父视图/图层时重新缩放子图层似乎很奇怪。
您只需要缩放父图层,所有子项将依次缩放。
所有这些手动生成的夹紧和平移代码都充满了危险。它可以做到,但我发现你最终得意大利面。
将您的视图放在UIScrollView中,让它完成perfil
视图的压缩和平移工作。
这是UIScrollView平移和缩放的十亿个例子。如果您还没有,Google和SO会知道。
我希望在父视图的touchBegan事件中捕获子图层的平移。
这是我用来捕捉子层中的命中
- (CALayer *)hitTest:(CGPoint)thepoint
{
//
CGPoint cpoint = [self convertPoint:thepoint fromLayer:self.superlayer];
if (CGRectContainsPoint([self bounds], cpoint)) {
NSLog(@"hitme!");
return self;
}
return nil;
}
这是在父视图的touchesBegan / touchesMoved中。 (保持对滚动视图的弱引用)
// Handles the start of a touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger tcount = [touches count];
if(tcount == 1)
{
UITouch* touch = [touches anyObject];
CGPoint tpoint = [touch locationInView:self];
location = [perfil convertPoint:tpoint fromLayer:view.layer];
hitsublayer = [self hitTest:location];
if([hitsublayer isKindOfClass:[MySubBoxThing class]]){
//ensure that scroll view doesn't capture the event
scrollview.canCancelContentTouches = NO;
}
else {
hitsublayer = nil;
//or something else to do wit not touching a sublayer.
}
}
// Handles the continuation of a touch.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger tcount = [touches count];
if (tcount == 1 && hitsublayer) {
UITouch* touch = [touches anyObject];
CGPoint tlocation = [touch locationInView:self];
location = [perfil convertPoint:tpoint fromLayer:view.layer];
NSLog(@"new loc = %@",[NSValue valueWithCGPoint:location]);
hitsublayer.position = location;
}
}
// Handles the end of a touch event when the touch is a tap.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(@"touches ended");
scrollview.canCancelContentTouches = YES;
hitsublayer = nil;
//any other actions once finished drag of object
}
该代码既不完整也不检查bug,但应该让你接近。