سؤال

So I effectively have a image I'd like to zoom horizontally but also be able to respect the location of the pinch. So if you pinched on the left, It'd zoom into the left. Ideally, the points where you pinch would stay with your fingers.

My case is a little more specific, I'm plotting data on a graph, so I instead will be manipulating an array of data and taking a subset. However, I'm sure the math is similar. (BUT, I can't just use an Affinetransform as most examples I've found does)

Any ideas?

هل كانت مفيدة؟

المحلول

The default pinch gesture handler scales the graph around the point of the gesture. Use a plot space delegate to limit the scaling to only one axis.

نصائح أخرى

Do you use a UIScrollView? As far as I know, you'll get this behaviour for free.

I built the below solution for standard UIViews where UIScrollView and CGAffineTransform zooms were not appropriate as I did not want the view's subviews to be skewed. I’ve also used it with a CorePlot line graph.

The zooming is centred on the point where the user starts the pinch.

Here’s a simple implementation:

@interface BMViewController ()

@property (nonatomic, assign) CGFloat pinchXCoord; // The point at which the pinch occurs
@property (nonatomic, assign) CGFloat minZoomProportion; // The minimum zoom proportion allowed. Used to control minimum view width
@property (nonatomic, assign) CGFloat viewCurrentXPosition; // The view-to-zoom’s frame’s current origin.x value.
@property (nonatomic, assign) CGFloat originalViewWidth, viewCurrentWidth; // original and current frame width of the view.

@end

@implementation BMViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Setup the pinch gesture recognizer
    UIPinchGestureRecognizer *pinchZoomRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchZoomGestureDetected:)];
    [self.view addGestureRecognizer:pinchZoomRecognizer];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    self.originalViewWidth = self.view.frame.size.width;
    self.viewCurrentWidth = self.originalViewWidth;
}

- (void)pinchZoomGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
    CGPoint pinchLocation = [recognizer locationInView:self.view];
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        self.viewCurrentWidth = self.view.frame.size.width;
        self.viewCurrentXPosition = self.view.frame.origin.x;

        // Set the pinch X coordinate to a point relative to the bounds of the view
        self.pinchXCoord = pinchLocation.x - self.viewCurrentXPosition;
        self.minZoomProportion = self.originalViewWidth / self.viewCurrentWidth;
    }

    CGFloat proportion = recognizer.scale;
    CGFloat width = self.viewCurrentWidth * MAX(proportion, self.minZoomProportion); // Set a minimum zoom width (the original size)
    width = MIN(self.originalViewWidth * 4, width); // Set a maximum zoom width (original * 4)
    CGFloat rawX = self.viewCurrentXPosition + ((self.viewCurrentWidth - width) * (self.pinchXCoord / self.viewCurrentWidth)); // Calculate the new X value
    CGRect frame = self.view.frame;
    CGFloat newXValue = MIN(rawX, 0); // Don't let the view move too far right
    newXValue = MAX(newXValue, self.originalViewWidth - width); // Don't let the view move too far left
    self.view.frame = CGRectMake(newXValue, frame.origin.y, width, frame.size.height);
    NSLog(@"newXValue: %f, width: %f", newXValue, width);
}

@end

This is all that needs to be done to resize the horizontal axis of a UIView.

For Core-Plot, it is assumed the CPTGraphHostingView is a subview of the UIViewController’s view being resized. The CPTGraphHostingView is redrawn when its frame/bounds are changed so, in the layoutSubviews method of the containing view change the CPTGraphHostingView and plot area’s frame’s relative to the bounds of its parent (which is the view you should be resizing). Something like this:

self.graphHostingView.frame = self.bounds;
self.graphHostingView.hostedGraph.plotAreaFrame.frame = self.bounds;

I haven’t attempted to change data on the graph as it zooms, but I can’t imagine it would be too difficult. In layoutSubviews on your containing view, call reloadData on your CPTGraph.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top