UIScrollView Updating contentSize Causes Scroll - iphone

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).

Related

UIScrollView start scrolling threshold

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.

UIScrollView inside UITableView

i got a tableview and as a header i use amongst other things a scrollview.
All work ok in terms of scrolling apart from the fact that when i scroll down (or up) the tableview the scrollview "loses" the x,y coordinates.
for example if i scroll the scrollview on the headerview right to left (or vice versa) then the scrollOffset.x gets a value.
if i start scrolling the tableview then this value goes back to zero (although the scrollview doesnt lose the paging). If i go back to the scrollview and start scrolling again the scrollOffset.x gets its correct value again.
Anyway to "keep" the scrollOffset.x value when i scroll the tableview?
thanks
Considering that a tableView is a scrollView subclassed it seems like the problem is that scrollOffset.x is set by whichever scrollView you're currently scrolling inside of. Try adding tags to your table view and scroll view and add a variable to keep up with the scrollOffset.x for only the scrollView in your header.

UIScrollView - setting proper contentOffset for new contentSize yields undesirable empty space

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).

UIScrollView auto-scrolls to top after SetContentSize during orientation change - how can I prevent that?

I have a UIScrollView in which vertical only scrolling is enabled. I'm displaying a grid of buttons (similar to the photo viewer image grid). The grid has to be drawn differently based on screen orientation, so that all of the screen real estate is used. Given the size of my buttons, I can fit 3 per row in portrait, and 4 per row in landscape.
I reposition all of the buttons in: willRotateToInterfaceOrientation:duration and then call: setContentSize: on my UIScrollView. Everything seems to work just fine, with the exception of the auto-scrolling that occurs after the call to SetContentSize:. In other words, let's say I was in portrait, and scrolled 3/4 of the way down the list, when I rotate to landscape, it auto-scrolls all the back up to the top.
The interesting thing is, in the same scenario, if I were to do a small flick scroll up or down, and then immediately rotate the device, the scroll view redraws correctly, and retains the current scroll position!
So, to be clear, the culprit here seems to be SetContentSize:, but obviously I have to call that for the scroll view to scroll correctly.
Any ideas on how I can retain the current scroll position?
Thanks!
You might try implementing the UIScrollViewDelegate method scrollViewShouldScrollToTop:, which tells the caller whether to scroll to the top or not. You may have to have some flag in your delegate that indicates if a rotation is underway or not, because under normal conditions you may actually want the ability to tap the status bar and have the scroll view scroll to the top.
If, on the other hand, you don't ever want the scroll view to scroll to the top automaticlly, simply implement that delegate method and have it return NO.
I had this problem, just did this and it works well for me
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//calculate percentage down scrollview currently at
float c = self.scrollView.contentOffset.y / self.scrollView.contentSize.height;
//reposition subviews in the scrollview
[self positionThumbnails:toInterfaceOrientation];
//set the new scrollview offset to the same percentage,
// using the new scrollview height to calculate
self.scrollView.contentOffset =
CGPointMake(0, c * self.scrollView.contentSize.height);
}
In my case, I have a scrollview with a fixed width to device size, and variable height

UIScrollView won't scroll!

In IB I have my UIView. Then I have a sub-UIView with a UIScrollView as a sub view. Then the UIScrollView has a sub-UIImageView. The UIScrollView and UIImageView are the same size. They're much bigger than the UIView of which they are subviews. I assumed this would make scrolling work. It doesn't. Is some sort of code required for scroll views to work?
You need to set UIScrollView.contentSize to match the total scrollable size, which is your subview frame size in this case.
As mentioned in the accepted answer, you must set the UIScrollView's contentSize property.
This can be done in Interface Builder.
Select the scroll view
Select the 'identity inspect' in Utilities pane on the right
Under 'User Defined Runtime Attributes' click the '+' button
Set the 'Key Path' value to 'contentSize'
Set the 'Type' value to 'Size'
Set the 'Value' value to '{width, height}' (eg: '{320, 600}')
Build and run and your scroll view will scroll.
The content inset does not affect scrolling. See What's the UIScrollView contentInset property for?
To scroll, you have to make the scrollview's frame smaller than its content, the contained image or view.
This might be obvious to most, but I spent ages wondering why my UIScrollView wouldn't scroll so I'm posting what was stopping me in case it helps anyone else:
The UIScrollView has to be of the dimensions of the visible area in which you wish it to be presented and not the size of it's contents.
Ridiculous on my behalf I know, but just in case it helps someone.
I placed all the content of my scrollview in IB. (buttons, labels, text fields, etc). The full size is 500 tall.
I then resized it to 436 tall in IB.
Then in code, I put this is viewDidLoad:
optionsScrollView.contentSize = CGSizeMake(320,500);
So that leaves 64 pixels that I can scroll. It works perfectly.
I also placed "UIScrollViewDelegate" in the <> braces of #interface for my .h file and tied the delegate outlet of the scrollview to File's owner in IB.
I could solve the scrolling problem with the following answer:
https://stackoverflow.com/a/39945124/5056173
By me the trick was:
You now need to set the height of the content UIView. You can then either specify the height of the content view (blech) or use the
height of the controls contained within by making sure the bottom
control is constrained to the bottom of the content view.
I have set the height and width of the view inside the scrollView with center vertical and horizontal alignment and that was the reason, why it did not work!
After deleting this constraints, I need to add equal width (scrollView and the view inside the scrollView) AND I set the height of the view inside the scrollView directly with the content. Which means: The last element in the view must have a bottom constraint to the view!!
The other important thing that I don't see mentioned here is that UIScrollView does not play nicely with AutoLayout. If it seems like you've done everything correctly, check if your ViewController has autolayout turned on and, if so, turn it off.
(Every time you scroll, the views are re-laid-out. Gak!)
So:
Make sure scrollview's contentSize is bigger than its frame.size
Make sure AutoLayout for the ViewController is turned off.
more, did you enable scrolling?
look at the property
#property(nonatomic, getter=isScrollEnabled) BOOL scrollEnabled
Make sure 3 things,
checking scrollView frame & contentView frame, u may find the answer
scrollView.isScrollEnabled = true
contentView of scrollView height didn't constraint with scroll view height
UIScrollView won't scroll!
reason: contentSize is same as (sub) view
should: contentSize is large than (sub) view
-> UIScrollView can scroll
how set UIScrollView contentSize?
two method:
in code
- (void)viewDidLoad {
[super viewDidLoad];
。。。
//[(UIScrollView *)self.view setContentSize:CGSizeMake(375, 1000)];
CGSize curScreenSize = UIScreen.mainScreen.bounds.size;
CGFloat scrollWidth = curScreenSize.width;
CGFloat scrollHeight = curScreenSize.height * 2;
[(UIScrollView *)self.view setContentSize:CGSizeMake(scrollWidth, scrollHeight)];
in UI (Storyboard)
Storyboard-》Identity Inspector-》User Defined Runtime Attributes-》 add new attribute:
contentSize
Type:Size
Value:{375, 1000}
Scroll view works with this:
Frame
then
contentSize
views or objects etc...
If your frame is set to your content size then it won't scroll.
So set your frame ( in IB right panel -> second last tab 'Size Inspector") to the length of your app ( in my case it is 367 as i have a navbar and a tab bar) then programatically set the contentSize to - yup you guessed it ... more than your frame so it can scroll.
Happy days!!