So the contentSize of my scrollView is initially equal to the frame of my image, but it seems that the more I zoom, the larger the contentSize gets. Thus, when the scrollView is zoomed in, , there is a huge gap around it. Dynamically updating the contentSize in - (void)scrollViewDidZoom:(UIScrollView *)aScrollView doesn't seem to work. Am I missing something?
Note: the gap is only visible vertically (i.e: above and below the imageView)
I don't believe it is possible to update contentSize on the fly while zooming. This is because:
A scroll view also handles zooming and panning of content. As the user
makes a pinch-in or pinch-out gesture, the scroll view adjusts the
offset and the scale of the content. When the gesture ends, the object
managing the content view should should update subviews of the content
as necessary. (Note that the gesture can end and a finger could still
be down.) While the gesture is in progress, the scroll view does not
send any tracking calls to the subview.
(Apple docs)
You should update your contentSize based on zoomScale after the user has finished zooming using:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView
withView:(UIView *)view
atScale:(float)scale
Related
I have a UIScrollView in the centre of the whole view which is separated in to three parts and scroll horizontally.
Users can scroll the view freely and when the finger is up, i want to set one of the three parts to show based on the contentoffset of the UIScrollView.
how could i detect the touchupinside event in the UIScrollView? I tried add UITapGestureRecognizer and override touchesEnded but it does not work.
How about instead using the - scrollViewDidEndDecelerating:?
Keep in mind that just because the user has picked up their finger doesn't mean that the scrollview has stopped changing its content offset. By utilizing the - scrollViewDidEndDecelerating: delegate method, yo will be notified when the scroll view has come to a stop and at that point you can check the contentOffset and do what you need.
- scrollViewDidScroll: isn't a good match for what you want as it gets called even while the user's finger is still down. If that is important to you, then use - scrollViewDidEndDecelerating: as I mentioned above. If you'd rather know when the finger is lifted, and don't care that the scrollview is still in transit, then you can use - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate.
iOS 8, Swift.
I'm trying to have a vertically scrolling view over a horizontally scrolling view. They're both UIScrollViews. The vertical scroll view is there to allow swiping up a view from the bottom. There is a spacer view on top using auto layout that is 1 pixel wide but the screens height.
This works fine until the underlying view is itself a scrollview to support horizontal scrolling.
I somehow need to pass the left/right pan gesture to the subview which is a UIScrollView.
Currently, the top level vertical scroll view is capturing all the gestures and not letting the underlying horizontal scroll view see the events.
I've tried various combinations of hitTest, gestureRecognizer delegate methods, scrollview subclassing but having come up with a nice clean solution.
I can use hitTest to pass events to the underlying horizontal scroll view when tapping the empty space at the top of the vertical scroll view, but then the vertical scroll view never processes a pan or swipe up to reveal the content that should appear on a swipe up.
Ideally, I'd like the top vertical scroll view to only handle pan up/down, and pass left/right pan to subview when the vertical scroll view is at the top.
Here's a brief method that may help you out:
Obj-C:
create scroll view that is invisible, and then pass the offset of the invisible scroll view or the touch events to the scroll views below depending on the offset of the touch events on the top invisible scroll view that covers the two underlying scroll views:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
[_verticalScrollView setContentOffset:CGPointMake(0, _insivibleScrollView.contentOffset.y)];
[_horizontalScrollView setContentOffset:CGPointMake(_insivibleScrollView.contentOffset.x, 0)];
}
You create an invisible scroll view, and by invisible, I mean you may have to keep the alpha value at like 0.01. You don't allow user interaction for the horizontal and vertical scroll views, but instead use the method above so that when the user touches the invisible scroll view you translate those touches to the scroll views below that are locked down to respond to only the offset of the invisible scroll view. As you've stated in your comment, there's probably more to this answer for your individual needs, but this is the basic "foundation" that will give you the effect that you probably want.
Swift:
Same method as above, but here's the function that you'll need:
func scrollViewDidScroll(scrollView: UIScrollView!) {
verticalScrollView.contentOffset = CGPointMake(0, invisibleScrollView.contentOffset.y)
horizontalScrollView.contentOffset = CGPointMake(invisibleScrollView.contentOffset.x, 0)
}
I have a horizontal UIScrollView. I want to implement a custom animation instead of the default bounce, where I pull all the way past the right edge of the scroll view's content size, the scroll view fly back to (0, 0) content offset after releasing finger.
Is there a way to cancel the bounce animation, keep the content offset from resetting, and then perform my animation?
I found a solution to this problem. Just use the UIScrollView delegate method:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
Thinking extemporaneously, without testing in code, grab the contentOffset, then set it back with setContentOffset:... animated:NO. That should cancel the ongoing animation and transition instantly to the position given. Since the position given is the current position, it should just cancel the animation.
I have a UIScrollView which has two pages and only scroll horizontally.
The scrolling and paging is controlled using a UIPageControl. I have placed a UIImageView on the scrollView which contains an image of an iPhone (shown in red in the image below) that says Hello inside page 1.
I wanted to animate the UIImageView to rotate and change its position as shown in the image when the user scrolls from page-1 to page-2. Also the animation should ideally rotate back when the user is scrolling back from page-2 to page-1.
The animation or movement of the UIImageView is based on how much the user is scrolling horizontally and not based on time.
How can I rotate the UIImageView back and forth based on the scroll position of the UIScrollView?
Set a delegate for your scroll view. Probably you want your view controller to be the delegate. You need to add UIScrollViewDelegate to its list of protocols.
Then, in the delegate, implement scrollViewDidScroll:. In scrollViewDidScroll:, look at the scroll view's contentOffset. Based on the contentOffset, set the image view's transform and center to rotate and move it where you want.
To find by how much the scroll view has scrolled, you can check UIScrollView's contentOffset property:
contentOffset - The point at which the origin of the content view is
offset from the origin of the scroll view.
Then to rotate that image view, you could do this:
self.imageview.transform = CGAffineTransformMakeRotation(M_PI/2);
As far as the animation goes, I personally don't have much experience with it. But you could have a look at Simple Animation Using UIImageView.
I have a UIScrollView that is displaying some graphical data and it has a x axis at the top of the screen. Currently when you scroll down the x axis disappears because it is just a subview of UIScrollView but I want it pinned to the top of the screen at all times so the user can see the x axis values.
Typically I would just put this axis ontop of the scroll view, so that it doesn't scroll, but I still need it to scroll along with the UIScrollView whenever a horizontal scroll takes place because the x axis does not entirely fit in the view.
I'm not sure how to go about doing this. I've thought about a few approaches.
I could remove the x axis from the ScrollView and then put it in its own UIView and then use the scroll view delegate methods to sync the x axis with the scrollviews new position after and during a horizontal scroll.
I could somehow duplicate horizontal scroll events and pass them to the x axis view (which would be another UIScrollView in this case).
I'm hesitant to try number one because I think the animations would be jerky or at the very least out of sync with the horizontal scroll of the scroll view, I would like them to be completely in sync.
I'm hesitant to try number two because I'm not sure if that is even possible to do.
I'm looking for advice on how to approach this problem (preferably from somebody who has done something similar before).
Thanks in Advance!
I believe that your second approach will work. Make your view controller a UIScrollViewDelegate for the 2-way scrolling view and use scrollViewDidScroll: to synchronize the positioning by adjusting the scrolling header.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offset = [scrollView contentOffset];
CGPoint headOffset = CGPointMake(offset.x, 0.0f);
[self.headScroller setContentOffset:headOffset animated:NO];
}
This assumes that the 'headScroller' has user interaction turned off and has no delegate. It only scrolls under program control.