4

I need to change UIScrollView subviews according to their place on the screen, so that they will get smaller while moving up and bigger while moving down.

Is there any way to know the contentOffset with the change of every pixel? I catch the scrollViewDidScroll: method, but whenever the movement is fast there might be some 200pxls change between two calls.

Any ideas?

  • you will have to deal with the 'jumps' as the scrollview can not provide you with every pixel. Think about a scroll-speed faster than the event-loop, this will always result in a offset-change greater than 1. – Jonathan Cichon Jan 21 '13 at 09:12
  • You sure you want UIScrollView for that? UIView is enough for that, just use @sergio's answer on UIVIew. – folex Jan 21 '13 at 09:19

1 Answers1

3

You have basically two approaches:

  1. subclass UIScrollView and override touchesBegan/Moved/Ended;

  2. add you own UIPanGestureRecognizer to your current UIScrollView.

  3. set a timer, and each time it fires, update your view reading _scrollview.contentOffset.x;

In the first case, you would do for the touch handling methods:

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {

UITouch* touch = [touches anyObject];
   _initialLocation = [touch locationInView:self.view];
   _initialTime = touch.timestamp;

   <more processing here>

  //-- this will make the touch be processed as if your own logics were not there
  [super touchesBegan:touches withEvent:event];
}

I am pretty sure you need to do that for touchesMoved; don't know if you also need to so something specific when the gesture starts or ends; in that case also override touchesMoved: and touchesEnded:. Also think about touchesCancelled:.

In the second case, you would do something like:

//-- add somewhere the gesture recognizer to the scroll view
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
panRecognizer.delegate = self;
[scrollView addGestureRecognizer:panRecognizer];

//-- define this delegate method inside the same class to make both your gesture
//-- recognizer and UIScrollView's own work together
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
   return TRUE;
}

The third case is pretty trivial to be implemented. Not sure if it will give better results that the other two.

sergio
  • 68,819
  • 11
  • 102
  • 123
  • 1
    this methods also will not be called on every pixel-change. Fast finger-movement will also result in great changes between two calls. – Jonathan Cichon Jan 21 '13 at 09:18
  • 1
    @Jonathan Cichon: you are right in that aspect. I added a third method, using a timer, but there will always be a fast enough movement that will defeat pixel-perfect detection. – sergio Jan 21 '13 at 09:27
  • 1
    i dont think the 3rd method will get better results, i used some key-value-observing on a uiscrollview some time ago, and the kvo did get called exactly as often as the `scrollViewDidScroll:` so i asume the delegate is called when ever the property changes. – Jonathan Cichon Jan 21 '13 at 09:30
  • 1
    Thanks Sergio. These methods will not provide me exact offset for each pixel change, since there is a UIScrollView's movement and deceleration after end touches. – Vadim Fainshtein Jan 21 '13 at 09:46
  • 1
    Hi Sergio. Didn't fully understood your comment on the first read. Will give it a chance now, it should work. THANKS! – Vadim Fainshtein Jan 21 '13 at 13:31