1

放大屏幕时,uipangesturerecognizer 出现问题。

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

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

这个 calayer 有几个子层,用户可以拖动 (uipangesture)、添加 (uitapgesture) 和删除 (doubletapgesture)。为了更准确地拖动,我在 uiview 中添加了一个 uipinchgesture 方法来放大和缩小。

此时一切正常,除非我放大并尝试移动(pangesture)子图层。有时有效,但通常无效(不放大总是可以正常工作)。

我不知道我的代码是否有问题,或者可能不是这样做的方法。有什么我想念的吗?

我在sdk 4.2下。

这些是我的代码:

    - (id)initWithFrame:(CGRect)frame
    {
        [超级 initWithFrame:frame];
        (……)
        perfil = [[CALayer alloc] init]; //uiview的图层
        [perfil setBounds:CGRectMake(0, 0, wide, heigth/2)];
        [[自层] addSublayer:perfil];

        //当用户触摸“编辑按钮”时,我将子层添加到“危险”层,效果很好

        //UIGsture 识别器
        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 需要GestureRecognizerToFail:doubleTapRecognizer];
        singleTapRecognizer.delegate = self;
        doubleTapRecognizer.delegate = self;
        pinchGestureRecognizer.delegate = self;
        panGestureRecognizer.delegate = self;

        //这里有一些其他不同的东西
    }

    - (void) handlePanFrom: (id)sender
    {
        CGPoint 点 = [(UIPanGestureRecognizer*)sender locationInView:self];
        boxLayer = [[self perfil] hitTest:point];
        [自己成为FirstResponder];

        if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan)
        {
            numberOfSublayer = 1000; //在 UIView.h 中声明为 int

            for (CALayer *elements in [perfil sublayers])
            {   
                if([boxLayer isEqual:elements])
                {
                    numberOfSublayer = [[perfil sublayers] indexOfObject:elements];
                    休息;
                }
            }
        }
        (…) //找到子层后的一些操作
    }

    - (void) handlePinchFrom: (id)sender
    {   
        if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded)
        {
            lastScale = 1.0;
            返回;
        }

        if ([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan ||
            [(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged) {

            CGFloat currentScale = [[[sender view].layer valueForKeyPath:@"transform.scale"] floatValue];

            常量 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);
            [发送者视图].transform = transform;

            if ([perfil 子层])
            {
                for (CALayer *elements in [perfil sublayers]) //这里我尝试调整缩放到子层
                {
                    //这是第一种方法
                    //CGAffineTransform transformELS = CGAffineTransformScale([元素 affineTransform], 7/(newScale+6), 7/(newScale+6));
                    //[元素setAffineTransform:transformELS];

                    //这里是第二种方法
                    [元素设置边界:CGRectMake(0, 0, elements.bounds.size.width*7/(newScale+6), elements.bounds.size.height*7/(newScale+6))];
                }           
            }

            lastScale = [(UIPinchGestureRecognizer*)sender scale];
            (...) //这里有一些其他不同的东西
    }

非常感谢你。

4

2 回答 2

1

终于我找到了我的问题的答案。这篇文章解释了完全相同的问题,它的解决方案对我来说非常有效 UIPanGestureRecognizer 起点是 off。谢谢。

于 2012-06-23T11:01:26.817 回答
0

如果没有看到子层 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 中。(保持对滚动视图的弱引用)

// 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


}

该代码既不完整也不检查错误,但应该让你接近。

于 2012-06-10T11:47:38.277 回答