放大时,UIPanGestureRecognizer不起作用

时间:2012-06-10 09:48:03

标签: iphone zoom uipangesturerecognizer

当我放大屏幕时,我遇到了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
    }

非常感谢。

2 个答案:

答案 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,但应该让你接近。