使用捏合手势放大自定义图形

时间:2014-01-04 08:17:51

标签: ios cocoa-touch uiview graph zooming

我正在使用CoreGraphics从两个NSArray对象的数据中绘制图表(一个包含水平数据的数组,一个包含垂直数据)。虽然这可行,但我想实现缩放功能,以便当用户捏住图表时,可视数据会根据其缩放进行缩放。

这样就像这样: enter image description here

成为这样的: enter image description here

我已经有一个名为dataRange的变量,当渲染图形时,它被限制在这个值范围内。 dataRangeNSRange,意味着它由起始位置和长度指定。但是,我不确定如何计算这些值,因为用户正在捏出来产生缩放效果。

在考虑如何实现这一目标后,我想出了以下内容:

  1. 确定每个手指在屏幕上的位置,并找出我需要放大的数组中的元素

  2. 随着位置越来越接近图表的两侧,相应地设置可见数据的范围

  3. 但是,该方法存在一些问题。首先,它忽略了图形是否先前已放大,这意味着用户无法放大多次。它也与您期望的相反,因为捏合增加了可见数据的范围(缩小),而捏合意味着减小可见数据的范围(放大)。我想要与此相反。

    执行此操作的代码在-touchesMoved:withEvent

    中实现
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        NSSet *allTouches = [event allTouches];
    
        if ([allTouches count] == 2) {
            CGFloat xPositionStart = 0.0f, xPositionEnd = 0.0f;
            CGFloat touchPositions[2] = {0.0f, 0.0f};
    
            for (UITouch *object in allTouches) {
                CGPoint touchLocation = [object locationInView:self];
    
                if (touchPositions[0] == 0.0f) {
                    touchPositions[0] = touchLocation.x;
                } else {
                    touchPositions[1] = touchLocation.x;
                }
            }
    
            if (touchPositions[0] > touchPositions[1]) {
                xPositionEnd = touchPositions[0];
                xPositionStart = touchPositions[1];
            } else {
                xPositionStart = touchPositions[0];
                xPositionEnd = touchPositions[1];
            }
    
            CGFloat xPositionStartActual = (xPositionStart / self.frame.size.width) * [self.horizontalValues count];
            CGFloat xPositionEndActual = (xPositionEnd / self.frame.size.width) * [self.horizontalValues count];
    
            self.dataRange = NSMakeRange(xPositionStartActual, xPositionEndActual - xPositionStartActual);
            [self setNeedsDisplay];
        }
    }
    

    我有点陷入困境,因为我无法找到用现有方法解决这些问题的方法。如果有人能指出我做错了什么,我会很感激。

2 个答案:

答案 0 :(得分:1)

您可以使用UIPinchGestureRecognizer进行自定义缩放。这就是我完成同样任务的方式:

- (void)pinchToZoom:(UIPinchGestureRecognizer *)recognizer {

    NSUInteger numTouches = [recognizer numberOfTouches], i;
    for ( i = 0; i < numTouches; ++i ) {
        CGPoint location = [recognizer locationOfTouch:i inView:self.view];
        // now you can do something with points of your pinch if you wish
    }

    // next calculate the current zoomScale TAKING INTO ACCOUNT previous value
    if (fabs(previousPinchScale - recognizer.scale) > 0.01) {

        previousPinchScale = recognizer.scale;
        zoomScale = beginScale * recognizer.scale;
        if (zoomScale < minimumCameraScale) zoomScale = minimumCameraScale;
        if (zoomScale > maximumCameraScale) zoomScale = maximumCameraScale;

        // now make the zoom using CGAffineTransform
        CGAffineTransform affineTransform = CGAffineTransformMakeScale(zoomScale, zoomScale);
        [CATransaction begin];
        [CATransaction setAnimationDuration:duration];
        [self.layer setAffineTransform:affineTransform];
        [CATransaction commit];
    }
}

现在我解释一下我使用的每个浮动属性是什么意思:

previousPinchScale - 一个变量,用于确定您是否捏合某个重要比例(大于0.01)。这是因为没有多次调用setAffineTransform,因为它的动作非常慢。在init方法中设置previousPinchScale = -1。

beginScale - 用于自定义缩放平滑查看的变量。您可以在委托方法中设置它:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if ( [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] ) {
        beginScale = zoomScale;
    }
}

zoomScale - 一个确定图形当前缩放的变量(如UIScrollView属性)。

minimumZoomScale,maximumZoomScale - 应该是明显的:)

这是一般方法,它可以缩放整个图形。 如果您只想缩放它的某些部分,可以将affineTransform应用于此部分,而不是整个视图。如果要实现缩放的“反向”效果,可以将所有浮点值乘以-1。您还可以根据用户捏的点来添加图形的一些偏移量。

我希望所有这些对你有所帮助。

祝你好运!

答案 1 :(得分:0)

您不希望缩放比例,因为它会缩放所有内容。尝试缩放内容视图的宽度和高度约束。将图表视图放在滚动视图中作为内容视图。