UIScrollView inner boundaries issue - ios

So I have a strange bug in my code that is confusing me...
In the screenshot below, I have a UIScrollView. In the Storyboard, I set the background color to Red. Then using a bit of code, I set the boundaries so that there is a tiny gap between the title bar area and footer (The yellow slivers).
The problem is that when I scroll the scroll view All the "bottom", the scroll bar is not actually at the bottom of the UIScrollViews boundaries. This behavior is also mirrored when you scroll all the way to the top of the scrollview, and so it adds an ugly space to the top of the scrollview.
Is there some sort of separate bounds that I should set for the inner size of the scrollview?
Code:
CGFloat navBarHeight = self.navigationController.navigationBar.frame.size.height;
CGRect screenRect = [[UIScreen mainScreen] bounds];
self.productScrollview.frame = CGRectMake(0, navBarHeight+22, screenRect.size.height, screenRect.size.width-footerHeight-navBarHeight-23);
self.productScrollview.contentSize = CGSizeMake(self.productScrollview.frame.size.height, self.productScrollview.frame.size.width);
self.productScrollview.contentSize =CGSizeMake(screenRect.size.width, 700);

Related

UIScrollView Bounces To Either Top Or Bottom

I have a UIScrollView for which I have a UIView which is the subview of the scroll view , the UIView has a lot of other subviews and I am getting the height for it dynamically after adding the subviews , this is my piece of code to add the view to scroll view
CGRect frameOfView = CGRectMake(0, 0,Get_Bounds.width, globalYPosition);
self.parentProductDetailView = [[UIView alloc]initWithFrame:frameOfView];
I am first initialising the view this way and then after adding all subviews I am doing this,
frameOfView.size.height = globalYPosition;
[self.parentProductDetailView layoutSubviews];
self.parentProductDetailView.frame = frameOfView;
[self.productDetailScrollView addSubview:self.parentProductDetailView];
self.productDetailScrollView.contentSize = CGSizeMake(0, self.parentProductDetailView.frame.size.height *1);
But my scrollview does not scroll properly it either sticks to top or bottom.
Here globalYPosition is the sum of height of all subviews added to parentProductDetailView
The procedure you used seems correct. No matter the subviews your scroll view should scroll properly by simply using a larger content size then its frame size.
The scroll view may stick, snap to some points if paging is enabled which is what is happening in your case. If the content view is larger then 1.5th of the frame size then the scroll view will snap to top/bottom or left/right. If it is smaller then it will only snap to starting position.
This may be very useful for situations like having a side menu that takes a part of a screen but in your case you should simply disable the paging and scrolling should work fine.

Scrollable UITableView as an overlay

I'm trying to replicate the following GIF from Postmates checkout - a scrollable UITableView positioned on top of a MapView. This tableview can be scrolled, with the normal bounce effect if I go too far down or up.
Currently, I have the MapView and UITableView added as sibling views to my ViewController's view. I have adjusted the frame of the table view to move it down.
CGRect rect = CGRectMake(
0.f,
200.f,
self.view.bounds.size.width,
self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height - 200.f
);
The two main issue's I'm having are:
I cannot figure out how to drag the entire tableview down when pulling down. E.g. the grey (my tableView.backgroundColor) sticks when I scroll down. If however, I make that background clear, then when I drag up, you see the map emerging from behind the view.
My cells keep disappearing when I scroll up. I have clipsToBounds = false, and I'm not actually dequeuing cells, just creating them in my cellForRow method, but they still disappear.
I feel like this should be a straightforward layout, but I'm missing something!
I've tried adjusting the contentInset of the table view, but then the scrollbar does not align with the cells as it does in the gif and does not look nice.
We needed similar effect in our app, along with parallax in the underlying view(map here/ we had a photos gallery).
I assume you want something like shown on this blogs video here
I wrote a small blog on how to achieve this. You can find this here
Basically its just a play of contentInsets and contentOffset properties of UITableView
If this does not suits you, here my suggestion in your two main points.
Controller's View has subviews
Map View (fills complete super view)
UITableView (fills complete super view) and in code set content insets.top = kHeightOfVisibleMap
The solution was simpler than I thought, no autolayout or crazy weird tricks required.
Add a full screen table view to your controller, and insert a full screen map view behind it.
self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
[self.view insertSubview:self.mapView belowSubview:self.tableView];
Add a dummy view with the background color of your table view with a height of around 200 pixels, and a full width, into the tableFooterView on your table view.
CGFloat footerHeight = 200.0;
UIView *dummyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, footerHeight)];
dummyView.backgroundColor = [UIColor whiteColor];
self.tableView.tableFooterView = dummyView;
Set the content offset of the table view to be the inverse of that footer view's height:
CGFloat footerHeight = dummyFooterView.bounds.height;
self.tableView.contentOffset = CGPointMake(0, -footerHeight);
Set the content inset of your table view to offset the footer view.
self.tableView.contentInset = UIEdgeInsetsMake(footerHeight, 0, -footerHeight, 0)
Adjust the scrollbar position, again, based on the footer's height.
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(footerHeight, 0, 0, 0);
This will push down the tableview, ensure the scroll bars match the table view, but allow it to bounce 'up' above its initial position and will ensure the background does not peek through the bottom of the tableview.

Why is my UIView's frame changing unexpectedly after the embedded UITableView is interacted with?

Consider the following UIView "MainView":
The view includes a Container View which in turn houses a UITableView controller. The container view's y coordinate starts just beneath the gradient bar. The UITableView includes the section footer at very bottom with the 'STU' label and 'chart' button.
When the UIView loads, and up-to-and-until any interaction with the tableView, MainView's dimensions are:
Frame: 0.000000x, 0.000000y, 568.000000w, 268.000000h
I have a delegate protocol set up such that tapping the chart button in the tableView will create a new view in MainView for a shadow effect via a method performing:
CGRect newFrame = self.view.frame; // self = MainView
newFrame.size.width = 100;
newFrame.size.height = 50;
UIView *backgroundShadowView = [[UIView alloc] initWithFrame:newFrame];
backgroundShadowView.backgroundColor = [UIColor blackColor];
// Do Animation
The important part above is the 'newFrame' CGRect. For some reason after interacting with the table view by tapping the chart button, or even scrolling or tapping a row, self.view.frame suddenly has the following dimensions:
Frame: 0.000000x, 52.000000y, 568.000000w, 268.000000h
And so the shadow view appears as follows, with a y origin much farther down than where it would be expected to start, just above the gradient bar.
I've adjusted the width and height of the "shadowview" for this question; normally it would be 568x268, but would extend 52 units off screen on the bottom because of this issue.
52 units is exactly the height of the statusbar (20) + navigationbar_in_landscape (32).
Of course I could manually adjust the frame dimensions, but I do not want to. I want to know why the view's frame is changing unexpectedly.
For the life of me, I cannot figure out why the view becomes suddenly offset. Any help is appreciated!!
Two comments.
(1)
This code was probably always wrong:
CGRect newFrame = self.view.frame; // self = MainView
newFrame.size.width = 100;
newFrame.size.height = 50;
UIView *backgroundShadowView = [[UIView alloc] initWithFrame:newFrame];
You surely want to define backgroundShadowView's frame in terms of self.view's bounds, not its frame as you are doing in the first line here.
(2)
The change in self.view.frame is probably illusory. You are probably checking this initially in viewDidLoad. But that is too soon; the view has not yet been added to the interface, and so it has not yet been resized to fit the surroundings.

Can't add a UIScrollView to a part of the view

Inside a UIViewController, I need to have the bottom half scrollable. So I added a UIScrollView and positioned it halfway down the view's height. And in the viewDidAppear method, I have put the below two code lines to make it scrollable.
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.scrollView.frame.size.height);
self.scrollView.frame = self.view.frame;
This way works if the scroll view fills the entire view, I've tested. But this method didn't work for my need. The scroll view would automatically move up and take up the entire screen. I assumed it was the second line of code which causes this.
So I removed the scroll view, added two UIViews to the view controller. To the bottom view, I added the UIScrollView. And in the viewDidAppear method, I have put the same two code lines changing the second line to refer the frame of the UIView that contains the scroll view..
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.scrollView.frame.size.height);
self.scrollView.frame = self.containerView.frame;
But it wouldn't scroll either.
Can anyone please tell me how to do this correctly?
Thank you.
Dude, you keep setting the frame of the scrollView to something completely different from what you're actually trying to achieve.
If all you want to do is setup your scroll view so that it only occupies half the space then why dont you just set the frame so that the height only covers the portion of the screen that you want it to cover; and then set the x & y coordinates so that you draw the scroll view from the right position.
Do something like this:
//Shortcut to view's frame.
CGRect viewsFrame = self.view.frame;
/**
CGRectMake takes 4 parameters: x, y, width, height
x: is set to 0 since you want the scrollview to start from the left with no margin
y: you want the y position to start half way, so we grab the view's height and divide by 2
width: you want your scrollview to span from left to right, so simply grab the view's width
height: you want your scrollview's height to be half of your screen height, so get view's height and divide by 2.
*/
CGRect frameForSV = CGRectMake(0, viewsFrame.size.height/2, viewsFrame.size.width, viewsFrame.size.height/2);
UIScrollView *myScrollView = [[UIScrollView alloc] initWithFrame:frameForSV];
[self.view addSubview:myScrollView];
Then set your content size not based on an ansolute value, its best to have it based on the size of the content that's actually inside your scrollview so that your scrollview always scrolls to cover all your content inside it.
Also, remember that your scrollview will only scroll if the contentsize is greater than the scrollview's frame
UPDATE 1 after reading your comment in this post simply comment out any code in your viewController.m file related to your scrollview since youre setting up everything in interface builder.
This is the result:

UIScrollView does not scroll down

I faced a strange problem, the scrollview does not scroll down, only scroll up. I have scrollview in my app, please look at my coding
.....
self.scrollView = [[UIScrollView alloc] initWithFrame: CGRectMake(0, 0, 320,427)];
[self.view addSubViews: self.scrollView];
UIView *blueView = [[UIView alloc] initWithFrame: CGRectMake(0, 47, 320, 320)];
blueView.backgroundColor = [UIColor blueColor];
[self.scrollView addSubViews: blueView];
self.scrollView.contentSize = CGSize(320, 640);
....
My problem is no matter what value I changed contentSize, my ScrollView only scroll up, not scroll down. I want user can move blueView to the top or bottom of iPhone screen from the original position.
do you have this problem?
The Problem
It looks like your issue is with how you're orienting blueView within scrollView. You're setting the frame of blueView to the CGRect (0, 47, 320, 320). When you set the frame like this, one of the things you're implicitly saying is:
The top edge of blueView is 47 points below the top edge of scrollView.
That's a perfectly valid thing to say, but it's what's causing the problem you describe. scrollView won't scroll down because it is designed to start, by default, with the rect (0, 0, 320, 480) in view. The contentSize property only indicates the size of the content within the UIScrollView, not its positioning. When you set it, you're basically telling scrollView:
Starting from your content origin, the content is 320 points wide and 640 points tall.
Thus, scrollView won't scroll up because, as far as it knows, there's no content above the coordinate (0, 0).
The Solution
There are three steps you'll need to take to get the functionality you want.
Set the contentSize to be just big enough to allow blueView to scroll all the way up and down.
Put blueView in the vertical center of scrollView.
Scroll the scrollView so that it is initially centered on blueView.
Set the contentSize to be just big enough to allow blueView to scroll all the way up and down.
We'll want to calculate the correct value of the contentSize property. It is of the type CGSize, so we need two parts: width and height. width is easy – since you don't seem to want horizontal scrolling, just make it the width of the screen, 320. Height is a little more tricky. If you want blueView to just touch the top and bottom of the screen when scrolled up or down, you need to do some math. The correct total height will be double the height of the screen, minus the height of blueView. So:
scrollView.contentSize = CGSizeMake(320, 480 * 2.0 - blueView.frame.size.height);
Put blueView in the vertical center of scrollView.
That's easy; just set the center property of blueView:
blueView.center = CGPointMake(160, scrollView.contentSize.height / 2.0);
Scroll the scrollView so that it is initially centered on blueView.
If you check the Apple UIScrollView documentation, you'll see an instance method - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated. This is exactly what you need to scroll scrollView programmatically. The rect you want is the one centered on blueView, with the size of the iPhone screen. So:
CGRect targetRect = CGRectMake(0, scrollView.contentSize.height / 2.0 - 240,
320, 480);
[scrollView scrollRectToVisible:targetRect animated:NO];
Make sure you do this scrolling in viewWillAppear, so it's ready right when the user sees the view.
That should be it. Let me know if you have any questions!
The content size of the scrollView should be the size of the view it is holding. This is how the code should be, try something like this.
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(X, Y, W, H1)];
UIView * blueView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, W, H2)];
self.scrollView .contentSize = blueView.frame.size;
[self.scrollView addSubview:blueView];
[self.view addSubView: self.scrollView];
Thanks to Riley. Here, the H1 is the height of the UIScrollVIew and H2 is the height of the blueView and (H1 < H2).

Resources