In UIScrollview, when I scroll/drag, I got changes in scrollview contentOffset which represent how much I had scrolled/dragged in the scrollview. By this way, I have updated the subview of scrollview for scrolling.
But, when I zoom the scrollview (using pinch zooming), the contentOffsets of the scrollview is also changed. I do not understand how much contentOffset has changed because I can not relate the changes with zoomScale value. So, is there anyway to know changes in contentOffset for zooming?
My intention is get the value of contentOffset changes for dragging while zooming (which is not I am getting because of zooming content offset changes) so that I can update my scrollview's subview accordingly.
I am stuck in here. Any help will be very much appreciated.
thanks
Shaikot
I've set up a small test project, and it looks like the contentOffset is multiplied by the zoomScale. So if you want to account for that, just divide it by the zoomScale before using it.
Maybe it's best to illustrate with a small example:
I've set up a scrollView, and added a view that's big enough to pan around and zoom a bit. To that view, I've added a small red view that I want to keep in the same position, no matter what.
I'm observing the contentOffset property of the scrollView, and I've implemented it like this:
CGPoint contentOffset = self.scrollView.contentOffset;
CGFloat zoomScale = self.scrollView.zoomScale;
self.moveView.frame = CGRectMake((contentOffset.x+10)/zoomScale,
(contentOffset.y+10)/zoomScale,
10,
10);
This keeps the moveView in the same position on the screen, only scaling it when the user zooms.
I hope this clears thing up a bit, but let me know if I can do more to help.
Related
I'm looking for a way of 'sticking' a UIScrollView to it's position unless the touch has been moved by a certain threshold, at which point it will jump to where it should have scrolled to and continue scrolling.
The reason for this is that I have a vertical scroll and each cell inside the UIScrollView has a horizontal scroll. So I'd like to introduce a slight 'stickyness' to make sure the user doesn't accidentally scroll vertically when they mean to scroll horizontally.
I started by hijacking the contentOffset property in scrollViewDidScroll. The trouble with that is I cannot find out how much the scrollView would have moved by if I were setting the contentOffset
If I try to add a UIPanGestureRecognizer to the class then it overrides the UIScrollView and the UIScrollView becomes unresponsive.
Does anyone know a way to do this?
EDIT: edits based on comments.
Lets say I add 10 views to a scrollview. I obviously give them a rect inside of the scrollview. Is there any way to figure out what each item's offset is in the scrollview?
I'm guessing that probably isn't applicable here. What I need in essence is, "If this item is at this content offset in the scrollview (meaning visible to the user in a certain area of the scrollview), then do this".
Each view's frame is expressed in its superview coordinate system (bounds). That is, in your case for each view its content offset is CGRectGetMinY(view.frame).
You might want to find the current scroll position by looking at UIScrollView contentOffset
The point at which the origin of the content view is offset from the origin of the scroll view.
With the contentOffset, you can then compare this with the frame x and y coordinates of the content views and determine if they are onscreen or not.
I have been juggling for a while with UIScrollView now. What I am trying is to insert subviews into the scrollView based on various factors. Since I have scrollview to scroll only in vertical direction, I would insert the subview before or after the current visible view.
So, lets say my current visible view's frames are (0,0,320,480), the contentSize of scrollView is (320,480) and current contentOffset is (0,0)
When I want to insert subview above the currentView and yet keep the currentView in focus, I insert the new subview at the position (0,-480,320,480) and change the contentSize of scrollView to (320, 960) while keeping the contentOffset same as (0,0).
The surprising thing which happens is, UIScrollView adds "extra" space after the currentView instead of inserting it above the currentView. While the newly inserted view above can never be brought into focus coz UIScrollView is assuming the contentSize from a wrong contentOffset perhaps!
I googled and found that there are some others facing similar problems, but did not yield results yet:
Set starting point of content size for UIScrollView
Please let me know if I am doing anything wrong? Or is this some kind of limitation etc?
Thanks!
Edit: Some threads suggests that changing the contentSize will affect contentOffset property, so to make sure that this is not causing problem, I am updating the contentOffset property only after I change the contentSize. Even then I am facing same problems.
You could solve this by :
adding your new subview with frame (0,0,320,480)
setting the frame of your existing subview to (0,480,320,480)
setting the contentSize to (320,960)
setting the content offset to (0,480) - not animated, of course.
So, in effect, moving everything down 480 points
The origin is always (0,0). If you want to insert something above the current offset you'll want to move the current views down by 480 points, add the new view at (0,0) and set the contentOffset to (0,480) (and the contentSize to (320,960).
I have a UIScrollView that has a single child view within it. If I set the contentSize of the UIScrollView immediately after creation, everything works as I expect and I get scrolling.
The challenge is the view within the UIScrollView is dynamically sized. The width is fixed, but the height is unknown at the time I set up the scrollview.
When I do a [scrollView setContentSize:CGRectMake(...)] after the inner view does it's thing, the scrollview updates to the proper size and scrolling works. So basic scrolling works fine.
However, the major problem is that when I setContentSize at a later point, the UIScrollView decides to scroll down(with animation) towards the end of the scrollview, which is not what I want, I want the scroll to stay at the top, and let the contents within the scrollview either get bigger or smaller, without changing the apparent scroll position.
What am I missing?
Why don't you also call [scrollview setContentOffset:CGPointMake(0,0)]; when you call the setContentSize?
To force UIScrollView to scroll only e.g. horizontally, I always set non-scrollable value for contentSize to 0, using:
CGSizeMake(contentSize.width, 0).
I have looked at UIScrollView. Any thoughts on implementing "infinite" scroll/zoom?, but it didn't exactly address my issue. I'm puzzled, though, because I would guess that other folks haven't seen my problem, so maybe it has to do with the details of my code. The sample code provided by Allisone is similar to mine, although I use scrollViewDidScroll to monitor the contentOffset instead of custom KVO approach.
When my UIScrollView is decelerating, if I insert a subview to the left of the UIScrollView's bounds and increase contentOffset by the width of my inserted subview, my change to contentOffset is ignored; the content "jumps" by the width of the inserted subview, and the contentOffset value stream continues on its current trajectory in subsequent invocations of scrollViewDidScroll. While simply tracking, there is no problem. Is there something I'm likely to be doing wrong? It's almost as if the bounds or contentOffset is sticky with regard to the deceleration events.
Use case: the UIScrollView has very large virtual content that is dynamically paged in and out, and when the user is smoothly scrolling through content in the UIScrollView (toward the left, say), additional content should be inserted on the far left of the scrollview without disrupting the smooth scrolling that is currently going on. As I said, this works fine if deceleration is disabled or I rely on dragging rather than flicking.
At first I hoped that the problem was caused by changing the contents of the UIScrollView from within the callout to scrollViewDidScroll, so I double-checked by doing a delayed performSelector, but the problem remained.
Thanks,
Kevin
Even though not exactly what you had in mind, but using setContentOffset:animated will have the desired outcome ( alter the content offset to the right coordinates ) although it will be animated.
Faced up with the same issue. Seems like strange UIScrollView bug. I fixed it on the base of StreetScroller example from Apple. InfiniteScrollView inherits from UIScrollView and works good in there. But if you want to create custom class which uses UIScrollView inside itself, you can subclass this UIScrollView and call delegate when it needs to recenter content like this:
tScrollView : UIScrollView
In tScrollView.m:
- (void)recenterIfNecessary {
if (_tDelegate && [_tDelegate respondsToSelector:#selector(offsetForRecenterScrollView:)])
self.contentOffset = [_tDelegate offsetForRecenterScrollView:self];
}
- (void)layoutSubviews {
[super layoutSubviews];
[self recenterIfNecessary];
}
Implement offsetForRecenterScrollView: in delegate and return new CGPoint to set in scrollView.contentOffset.