I've a problem with UIScrollView in iPhone with iOS 7
I created horizontal UIScrollView programmatically, I added some colored button and finally I positioned the scroll in the top of the screen.
The scroll is a custom scroll, so I can handle
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
return YES;
}
and
scroll.canCancelContentTouches = YES;
scroll.delaysContentTouches = YES;
to allow the scroll to move, even if I press a button
Everything perfect except the top of the screen, where the scroll doesn't move. But I can press the buttons.
If I position down the scroll (circa 30px) I can scroll it in its upper part (content size and frame are correct)
I removed the status bar of iOS 7 with info.plist setting "View controller-based status bar appearance = NO"
Seems that in the area of status bar I cannot drag the scroll.
Any suggestions?
EDIT: Interestingly, if before scrolling, you pull down the notifications tab, then the scroll works even in the upper part.
When notification tab move up, problem return.
As if the first touch was managed by the tab and not passes it to the scroll
Yeah, something strange happened with UIScrollView in pure autolayout environment. Re-reading the iOS SDK 6.0 release notes for the twentieth time I found that:
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints between the view and a view outside the scroll view’s subtree, such as the scroll view’s superview.
Solution
Connect your subview to the outer view. In another words, to the view in which scrollview is embedded.
As IB does not allow us set up constraints between the imageView and a view outside the scroll view’s subtree, such as the scroll view’s superview then I've done it in code.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view removeConstraints:[self.view constraints]];
[self.scrollView removeConstraints:[self.scrollView constraints]];
[self.imageView removeConstraints:[self.imageView constraints]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[_imageView(700)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_imageView(1500)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
}
And ! It works as Charm!!
Is your target iOS7 or earlier version? If it is iOS7 and you change to iOS6.1 and get the expected behavior, then it is most probably bug.
Another approach is also to check the auto layout constraints as already suggested from colleague and of course to watch the contentFrame property in connection with it.
Related
I feel like I have touched on every single possible cause for stopping this, but I have a UIScrollView in my Storyboard hooked up with an outlet and in the viewDidLoad I set the contentSize so that I can scroll (yes bigger than my frame size)!
However, whatever I change, I just can't scroll! I have a couple of textfields in my scrollview and bouncing enabled so I can see that when testing its moves up and down with my subviews in it but whatever I set the contentSize to I just can't scroll.
Anything I might be missing/should check? Is this a known issue with UIScrollView being used in a storyboard?
Whats even stranger is, I can do something like this:
[scrollView setBackgroundColor:[UIColor blueColor]]; and I have a blue scroll view! But setting content size fails.
Edit
My only code (otherwise scrollview is just dropped into storyboard view controller):
-(void)viewDidAppear:(BOOL)animated
{
[scrollView setContentSize:CGSizeMake(320, 640)];
}
Logged frame, comes out as expected:
width: 320.00
height: 504.00
Edit 2
Turns out that removing any subviews of the scroll view in my storyboard lets it scroll just fine. If I add any subview to it at all via the storyboard, even a blank brand new UIButton it just won't apply the contentSize/allow scrolling.
use ViewDidLayoutSubview
- (void)viewDidLayoutSubviews
{
[_scrollView setContentSize:CGSizeMake(320, 500)];
}
UIViewController's method invoke sequence is as below
awakeFromNib
viewDidLoad
viewWillAppear
viewWillLayoutSubviews
viewDidLayoutSubviews
viewDidAppear
viewDidLoad is not a good place to put code that relies on frame sizes of IB objects. If you log the contentSize of your scroll view in viewDidLoad, you will see that it's (0,0). Move the code (where you set the content size) to viewDidAppear, and it will work properly.
Check these
User Interaction enabled
Outlet connected
Included contentsize greater than bounds
scrolling Enabled
eg
scrollView.contentSize = CGSizeMake(320, 640);
My storyboard looks like this for scrollview [working]
I had exactly the same line of code in viewDidAppear and it did not work
Moved it to viewDidLayoutSubviews and it worked correctly.
[scrollView setContentSize:CGSizeMake(320, 500)];
Thanks trick14 for the answer.
The issue is most probably with Auto Layout. UIScrollView needs special attention when using AutoLayout.
Quick-fix - bind one of the scroll's subviews to the top AND bottom space of it's superview (the scroll view).
Long story:
Questions on SO:
UIScrollView not scrolling regardless of large contentSize,
UIScrollView will not scroll, even after content size set,
UIScrollView doesn't use autolayout constraints
Apple's Documentation:
https://developer.apple.com/library/ios/technotes/tn2154/_index.html
Trip14's answer worked for me. In swift I coded it as:
override func viewDidLayoutSubviews() {
(self.view as! UIScrollView).contentSize = CGSizeMake(600, 600)
}
This seems to be a similar issue. Other Story
It might be an issue with auto layout or constraints in the storyboard.
the best way with the storyboard.:
Okay, so the subject talks for itself - I need to change default scrollbar with my custom image. I've been looking for a solution that doesn't require you to write your own ScrollView class or use hacks like creating an UIView with scrollbar image and repositioning it as you scroll.
One solution I liked was to use a simple UIScrollView category and to access scrollbars as UIScrollView's subviews: http://leonov.co/2011/04/uiscrollviews-scrollbars-customization/#comment-7909 For some reason, though, this one doesn't work for me. When I create UIScrollView and get its subviews array only views that I manually add to scrollview are shown there. I cannot access scrollbars iterating through subviews array. For example, this code:
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(10,10,100,100)];
scrollView.userInteractionEnabled = YES;
scrollView.bounces = NO;
scrollView.showsHorizontalScrollIndicator = YES;
NSLog(#"Subviews count is %d", [[scrollView subviews] count]);
will log "Subviews count is 0". Or, if I add X elements to scrollview, "Subviews count is X". Any ideas?
UIScrollbar scroll views are only created when the view is scrolling. They are removed again when the view stops scrolling. That's probably why you can't find them with your category.
You could move your scrollview subview traversing code into the scrollview delegate's scrollViewDidScroll method, which would mean it gets executed whenever the view is scrolling.
I can't help but feel that this is all a horrible and unneccesary hack though, and you'd be better off hiding the scrollbars and implementing them yourself using the delegate methods to determine when to show and hide your custom scrollbar view and the contentOffset property to determine where to position it.
I"m relatively new to iOS development, as you can likely tell, and would like to display about 600 pixels worth of content (in height) on the screen. Just to give you a bit of context, I'm building a tab bar application, so what I'm assuming would be a UIScrollView cannot be defined in the App Delegate. Primarily, what I'm confused about is changing the size of the view and then defining the behaviour of the UIScrollView. I've looked everywhere, but they are all tutorials for < Xcode 4, plus none of them use the View Controller to define a scroll view. Is there a specific IBAction that would only allow the view to scroll up and down, not left and right. Any help would be appreciated.
Once you define the contentSize and assign a subview to the UIScrollView you should be able to scroll automatically.
To make sure you have vertical and horizontal scrolling you could do this -
[scrollview setBounces:YES];
[scrollview setShowsVerticalScrollIndicator:YES];
[scrollview setShowsHorizontalScrollIndicator:YES];
[scrollview setScrollEnabled:YES];
[scrollview setUserInteractionEnabled:YES];
If you want to add double-tap to zoom etc. you could do that too in similar way...
I'm having problems making my app iPad compatible.
I have an implementation of a custom Tab Bar, based on the post here http://www.wiredbob.com/blog/2009/4/20/iphone-tweetie-style-navigation-framework.html
That all works fine apart from when the device is rotated. The currently selected view rotates and resizes perfectly. Every other view rotates but does not resize to fill the space. There is a large white column down the right hand side.
I've tried adding
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view.autoresizesSubviews = YES;
to the tab controller view.
I've added similar code to the tab's views viewDidLoad methods.
I've tried to make the willRotateToInterfaceOrientation call all the subviews rotation methods but still no luck.
Any suggestions would be more than welcome at this stage. I'm hoping i'm not overlooking something obvious but i might be. I've been at it for a few hours now
Screenshot 1 -
Screenshot
Ok I Solved this problem.
What I had to do was manually call a resize on all the sub views. - i added a changeFrameSize function to each sub view (just so it made the code look a little nicer)
Oh and when adding views as sub views always use belowSubView method -
[self.view insertSubview:viewController.view belowSubview:tabBar];
-(void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[(ViewControllerClass *)[viewControllers objectAtIndex:0] changeFrameSize:[NSNumber numberWithFloat:self.selectedViewController.view.bounds.size.width] height:[NSNumber numberWithFloat:self.selectedViewController.view.bounds.size.height]];
[(ViewControllerClass *)[viewControllers objectAtIndex:1] changeFrameSize:[NSNumber numberWithFloat:self.selectedViewController.view.bounds.size.width] height:[NSNumber numberWithFloat:self.selectedViewController.view.bounds.size.height]];
[(ViewControllerClass *)[viewControllers objectAtIndex:2] changeFrameSize:[NSNumber numberWithFloat:self.selectedViewController.view.bounds.size.width] height:[NSNumber numberWithFloat:self.selectedViewController.view.bounds.size.height]];
}
So because the selected view controller was always rotated and resized to the correct size, once it had rotated and adjusted i simply passed the same parameters to the sub views so they would resize too.
I have a UIScrollView which I create and size dynamically using...
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width , length);
I then add subviews to the UIScrollView.
I do have scrollView.showsVerticalScrollIndicator = YES;
When scrolling the scroll indicator never appears.
Even if I call [scrollView flashScrollIndicators] nothing happens.
Ideas?
Had the same problem and couldn't find the cause. The last answer gave the final hint: whenever I added new subviews I first removed all existing subviews from the scrollview (and apparently also the scroll indicators).
After checking in my loop, if the subview really was of the kind I wanted to be removed the scroll indicators showed up:
for (NSObject * subview in [[[scrollView subviews] copy] autorelease]) {
if ([subview isKindOfClass:[MySubView class]]) {
[(MySubView*)subview removeFromSuperview];
}
}
Update: changed code to Nikolai's suggestion
When I've dealt with this before, in my implementation of a grid, I would occasionally get some cells over the top of the scroll indicator. To fix this I am now inserting subviews at index 0 rather than adding them, which adds them to the top. So try something like this:
[scrollview insertSubview:subview atIndex:0];
For me, the horizontal indicator had mysteriously disappeared in my app on iOS 7. Later found out that for some strange reason, I had to enable both Shows Horizontal Indicator and Shows Vertical Indicator to make the horizontal one show up. If I set it to not show the vertical indicator, it would also not show horizontal indicator.
I fix this by adding this code after add new subview:
self.showsVerticalScrollIndicator = NO;
self.showsVerticalScrollIndicator = YES;
It will also happen (at least in the case of a UITableView) if the contentSize is too small for the table view to scroll. If you have enabled bouncing, then the tableview does not actually scroll and does not display the indicators therefore. Try fitting more content inside.
It can happen also if the parent of the scrollview is smaller horizontally than the scroll view itself :
The scroll bar is stuck to the right side of the ScrollView / TableView and this right side is not visible due to the parent bounds ( with a clipToBounds hidding it for instance).
I've seen this issue so I share it in case it can help.
Just check the width of your ScrollView's frame not to be bigger than the width of its parent view frame.
Two conditions,
If you are using a storyboard
If you are using a UITableView inside a UIViewController
Then, you should check your indicator insets are set to 0 (or any other number that is relevant to your autolayout):
Noticed this when the UIScrollView was a 48 px tall horizontal band, scrollable horizontally. Maybe Cocoa decides the area is too small for a scroll indicator...