UIScrollView doesn't bounce - iphone

I have a UIScrollView contained within a custom UIView with a content size larger than the ScrollView's frame.
I am able to drag scroll as I expect, but the thing doesn't give me the rubber banding effect that you get with the UITableView or UIWebView. It just stops when you get to one of the extremes.
I have set bounce = YES, is there something else I'm supposed to do?
I read the docs, and they say I have to implement the delegate. I did that.
They also say I should change the zoom levels, but I don't want the user to actually be able to zoom so I haven't set these.

For anyone that finds this thread later, if you are subclassing UIView and re-setting the UIScrollView's frame on every layoutSubviews, that is the problem - it cancels the bounce:
http://openradar.appspot.com/8045239
You should do something similar to this:
- (void)layoutSubviews;
{
[super layoutSubviews];
CGRect frame = [self calculateScrollViewFrame];
if (!CGRectEqualToRect(frame, self.scrollView.frame))
self.scrollView.frame = frame;
}

I had the same problem, on a UIScrollView that wasn't all filled up (but I still wanted it to bounce). Just setted:
scroll.alwaysBounceVertical/Horizontal = YES;
And it worked as expected

It turns out that keeping the UIScrollView within my custom UIView was causing the trouble.
Once I switched my custom UIView to instead inherit from UIScrollView, then the bouncing started working.

That is interesting... Is there a lot going on while the user scrolls the scroll view? Maybe that could cause the problem. The iPhone can multitask, but not too much. Can I see your entire code having to do with the scroll view?

Related

Problem with UIScrollView inside another UIView

I have this UIScrollView inside another UIView, not occuping the entire area (all this is initialized via nib file). I added some content to the scroll view, but whenever I scroll it, the UIScrollView content area moves outside the ScrollView frame, over the UIView area not designated for displaying it.
Shouldn't it remain inside its frame even when I scroll it?
It may be that the clipsToBounds property of your UIScrollView is set to NO. Check the setting in IB, or you can set it in code like so:
scrollView.clipsToBounds = YES;
Failing that, double check that your UIScrollView has exactly the bounds you think it does. Is there any autoresizing flag stuff going on that might be changing the scroll view's bounds?
try to set the clipsToBounds to YES, it may be that:
yourViewController.clipsToBounds = YES;
if not... fbreto is right, post your code...
Make sure you have setContentSize. And also set the frame size of the uiviews inside the uiscrollview correctly when you add them.
Here is a sample code of it http://developer.apple.com/library/ios/#samplecode/Scrolling/Introduction/Intro.html

MKMapView inside a UIScrollView doesn't move with swipes

I've got a detail view with various labels and such providing information about a place (address, phone, etc.). The information provided is taller than an iPhone screen so they're all in a UIScrollView (itself inside a UIView) that allows you to swipe up and down to see everything.
I also have an MKMapView inside the scrollview. When it's not attached to anything in Interface Builder it moves up and down with the scrollview, as it should, staying in it's correct relative position to the other controls in the scrollview. You can play with the map, zooming and panning it, etc. and it shows your current location by default.
However, as soon as I hook it to an MKMapView variable in IB, the mapview no longer scrolls with the scrollview. Instead it literally just sits in the position it's originally displayed in (bottom of the view, with a little of the map hidden below the bottom of the view) and the scrollview scrolls up and down behind it.
What's happening here? I've tried changing a bunch of the mapview's and scrollview's properties in IB, but it has no effect. The only thing I haven't tried is just creating the mapview entirely in code, but that doesn't seem like an obvious solution.
EDIT: Sorry to everyone about the expired bounty. I got hung up in other areas of the project and couldn't get back here until now. I didn't know it would expire.
FURTHER EDIT: Well, I figured out my problem. For reasons completely unknown to me I had
[self.view addSubview:mapView];
in the viewcontoller's ViewDidLoad. Once it was hooked up then that line of code would (obviously) make the map a subview of my of view, effectively yanking it out of the scrollview.
Stupid mistake, sorry to have wasted your time (and the bounty). I'll delete this question after I think the answerers have had a chance to see the result.
Looking like as you are using the ScrollView,you need to scrolling facility in your DetailView.
Instead of using the ScrollView ,I had an alternative of this ....
You can try your hard luck by using the TableView instead of ScrollView.
Just take all the labels and mapView in a single View and then put that view in the header of the TableView.
like this :
UITableView
--> View
------>All Labels // Inside the singleView
------>MKMApView // At bottom of the View
Still You can play with the map, zooming and panning it, etc. and it will show your current location by default.
Hope this alternative can solve your problem.......
All the Best
If hooking up an outlet in IB is breaking an otherwise working view, you might be able to try this to locate the view at runtime:
- (UIView *) findClass:(Class) aClass inView:(UIView *) aSuperview {
for ( UIView *view in aSuperview.subviews ) {
if ( [view isKindOfClass: aClass] ) break;
if ( ( view = [self findClass: aClass inView: aSuperview] ) ) break;
}
return view;
}
- (void) viewDidLoad {
MkMapView *map = [self findClass: [MkMapView class] inView: self.view];
}
I figured out my problem. For reasons completely unknown to me I had
[self.view addSubview:mapView];
in the viewcontoller's ViewDidLoad. Once it was hooked up then that line of code would (obviously) make the map a subview of my of view, effectively yanking it out of the scrollview.
Do you have setContentSize property set to the content's size in the viewDidLoad method of the UIViewController?

Changes to UIScrollView contentOffset don't stick when decelerating

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.

How do I properly handle rotation of a UIScrollView containing UIImageViews?

I'm developing an image viewer, much like the Photos App.
It's a UIScrollView with paging enabled with images loaded from the internet, so I've adapted portions of the LazyTableImages sample. The Scroll View and each ImageView inside of it have all of their autoresize mask flags set.
When I first observed how resizes were happening during rotation, it looked good, but once I started trying to interact with the scroll view, I realized that I also had to programmatically change the size of the contentView. I did that by implementing didRotateFromInterfaceOrientation: in my view controller.
[self.scrollView setContentSize:CGSizeMake(numberOfImages * portraitWidth, [scrollView bounds].size.height)];
With interaction behaving properly, I then discovered that, if I was viewing the second photo and rotated, portions of both the 1st and 2nd photos would be shown on the screen. I needed to change the contentOffset as well.
I've tried to fix this two ways - both by using the scrollRectToVisible:animated: method of UIScrollView, as well as trying to set the contentOffset property directly. And I've experimented by putting this code in implementations of both the "one-step" and "two-step" responses to changes in Orientation. For example:
-(void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
[self.scrollView setContentOffset:CGPointMake(currentlyViewedPhotoIndex * largeImageHeight,0) animated:YES];
In all cases though, it just looks janky as hell. Either I clearly see the scroll happen, or it just jumps. Uuuuuuuuuuugly! Is there a way to do this so that it behaves exactly like the Photos app does?
What I wound up doing instead - just before rotation starts, hide the UIScrollView and create a UIImageView that contains the currently viewed image. Rotate, that image will rotate all nice and pretty, and when rotation completes remove the ImageView and unhide the Scroll View.
Update - if you're reading this today (anytime after iOS 6), use a UIPageViewController and set transitionStyle to UIPageViewControllerTransitionStyleScroll, for crissakes.
I did something slightly different when faced with the same problem. In willRotateToInterfaceOrientation:duration:, I hide all of the UIScrollView's subviews except for the currently displayed subview, and in didRotateFromInterfaceOrientation: I unhide the subviews.

iPhone Horizontal Scrolling

I am trying to create an app with horizontal scrolling, so that one would be able to scroll horizontally through a series of images. I watched the WWDC Session 104 video on this, and while they made an interesting app, they flew through the basics of it very quickly.
I understand using the UIScrollView, and that I have to enable paging. After that they say that I should add more views as subviews of the scrollview, but I am not clear on how to do that. I am also not clear on how I add my images to those views.
As you can probably tell I am pretty new at this so any help would be appreciated.
You want to look into UIImageView. It's a view specifically for holding images.
When you add your images, you want to set their rects (probably using initWithFrame: for each UIImageView) so that:
the first image is at 0,0
the second image is at 320,0
third is at 640,0 (etc)
I.e. each image is 320 pixels right of the previous.
The final step is to set the contentSize for your UIScrollView -- this is a CGSize which describes the total size of the scroll view.
If you have 3 images, you would then set it to (320*3) * 480 using e.g.
myScrollView.contentSize = CGSizeMake(320*3, 480);
A lot of people, when they initialize the scroll view, have a for loop or similar which steps through the images they want to display. These for loops tend to look something like this:
CGFloat scrollWidth = 0.f;
for (UIImage *someImage in someNSArrayWithImages) {
UIImageView *theView = [[UIImageView alloc] initWithFrame:
CGRectMake(scrollWidth, 0, 320.f, 480.f)];
theView.image = someImage;
[myScrollView addSubview:theView];
[theView release];
scrollWidth += 320.f;
}
myScrollView.contentSize = CGSizeMake(scrollWidth, 480.f);
This way you'll get things lined up and you'll get the content size for you at the same time.
If you want to make it so that the scroll view "intelligently" scrolls to each image and stops when people slide left/right, you can do myScrollView.pagingEnabled = YES.
Hope that helps get you going.
Assuming you have "infinite" images, putting them all there at or before launch time in a huge UIScrollView will not be an option. (there is a limit to the size of a UIView)
The way I solved it: Make a UIScrollView covering the whole screen. It's content should be a UIView of 3*320 width and 480 height, extending 320px left and 320px right.
Put 3 UIImageView's in it, left, middle and right. Set paging=YES, so the uiscrollview clips to the 3 "pages" you've created.
Make sure your class is the delegate of the uiscrollview, and listen for
-(void)scrollViewDidEndDragging:(UIScrollView*)sv willDecelerate:(BOOL)notFinished
-(void)scrollViewDidEndDecelerating:(UIScrollView*)sv
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView*)sv
and make the appropriate transitions on hitting paging boundaries; shift images and set ContentOffset so you're looking at the center image again.
I suggest you make this first, and only then read on...
Then you will hit on a bug, documented here UIScrollView - (bounces = NO) seems to override (pagingEnabled = YES) and here http://www.iphonedevsdk.com/forum/iphone-sdk-development/935-paging-uiscrollview.html, which makes that you cannot disable bouncing and have paging enabled at the same time. So enable bouncing, and subclass UIScrollView, overruling setContentOffset in there to prevent bouncing. (having bouncing really enabled will make for a rather unusual user experience)
Have a look at Apple's PageControl sample code. It's fairly short and easy to follow so you'll get the gist of setting up a project where multiple view controllers are loaded as you swipe horizontally.
Once you have this setup then it's the view controller's responsibility to load its own content (in your case, an image). You should make sure you understand how to load images first (using threads, etc) before you tackle paging, etc.
Think of it as two independent tasks. The view control is responsible for loading and displaying an image. The scroll view with paging just tells the appropriate view controller when to load itself (it doesn't care what the view controller does once its loaded)
Good luck!