首页 文章

放大时,UIPanGestureRecognizer不起作用

提问于
浏览
1

当我放大屏幕时,我的uipangesturerecognizer有问题 .

我的应用程序有一个带uiview的uiviewcontroller .

在这个视图中,我有一个几乎占整个屏幕边界一半的calayer .

这个calayer有几个子层,用户可以拖动(uipangesture),添加(uitapgesture)和删除(doubletapgesture) . 为了更准确地拖动,我在uiview中添加了一个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

    如果没有看到sublayer hittest代码真的很难说,但是当您重新缩放父视图/图层时,重新缩放子图层似乎很奇怪 .

    您只需要缩放父图层,所有子项将依次缩放 .

    所有这些手动生成的夹紧和平移代码都充满了危险 . 它可以做到,但我发现你最终得意大利面 .

    将视图放在UIScrollView中,让它完成 perfil 视图的捏合和平移工作 .

    这是UIScrollView平移和缩放的十亿个例子 . 谷歌和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中 . (保留对scrollview的弱引用)

    // 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,但应该让你接近 .

  • 1

    最后,我的解决方案对我来说非常有用UIPanGestureRecognizer starting point is off . 谢谢 .

相关问题