I'm in the midst of trying to use a UIScrollView and there appears to be some fundamental thing that I'm just not understanding.
Let's say I want to use a UIScrollView in my iphone app. I have a View filled with buttons that is 320x700. Obviously, this is too big for the iPhone which is 320x480. So I know I have to use a UIScrollView. However, is this the order that I should be creating the objects
Create a UIScrollView that is 320x700 as the dimensions in "View"
Place all my buttons, etc, on this scroll view
In the viewDidLoad set the contentSize to 320x700
Set the delegate of the UIScrollView to the File Owner, and the view of the FileOwner to the UIScrollView
Reset the size of the View back to 320x480.
Is this right?
This works, but it doesn't make sense to me. I get that the View is supposed to be the canvas, where I add all the UI elements. I want the "canvas" of the iPhone app to be 320x700, and I want to be able to put my buttons, etc on this 320x700 canvas. But if I don't change the size of the UIScrollView back to 320x480, it won't scroll, because I need to set the content size of the UIScrollView larger than its size.
But if I set the size of the UIScrollView to 320x480, then I don't see the screen and the buttons between 480 and 700 in Interface Builder! So it seems like I'm supposed to make all my edits and add all my UI elements to the UIScrollView, and then set it back to the 320x480!
Is there some other way to do this that makes more sense? What am I missing in my understanding of how this should work?
UPDATE
I have posted another solution here which I think is simpler and better.
ORIGINAL
Here's another way to do this that you might like better:
Set the File's Owner placeholder's custom class to your view controller subclass.
Create the UIScrollView as a top-level object in your nib. Set its size to the screen size (320x460) or just turn on a status bar under "Simulated Metrics".
Connect the scroll view's delegate outlet to File's Owner.
Set the File's Owner's view outlet to the scroll view.
Create a UIView as another top-level object in your nib. This will be your content view.
Set the content view's size to 320x700.
Create a strong (or retain, if not using ARC) outlet named contentView in your view controller (File's Owner) and connect it to the content view.
Put your buttons in the content view.
In your view controller's viewDidLoad, do this:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.contentView];
((UIScrollView *)self.view).contentSize = self.contentView.frame.size;
}
In your view controller's viewDidUnload, do this:
- (void)viewDidUnload {
self.contentView = nil;
[super viewDidUnload];
}
Full size
You are right, the View is the canvas where you add all the UI elements.
Interface builder is kind of weird at first but you will get used to it, that is just the way it works.
You are getting stuck on the fact that you have to resize the ScrollView. You should think of it like this:
The ScrollView has a frame size and a content size. The way it's built is that if the content size is larger than the frame size then it will scroll. You have to make the frame as big as you need to in the interface builder so you can position the elements that go inside. When you run the application you should resize the frame of the scroll to fit inside the iPhone's screen resolution. It doesn't make sense for your controls to have a frame bigger than the screen.
--------------------------------------------
| | | |
| | | |
| | | |
| | | |
| | |<------------------ iPhone Screen frame
| | | |
| | | |
| | | |
| | | |<------- ScrollView Content size
| | | |
| | | |
| | |<----------------- ScrollView Frame Size
| | | |
| | | |
| | | |
| | | |
| | | |
| ------------------------ |
| |
| |
| |
--------------------------------------------
I hope this representation will make it clearer how things should suppose to work.To put it some other way, the scroll frame is the hole trough you can see the content, if the whole is as big as the content then you have no need to scroll cos you can see it all.
I would suggest also trying to write the components in code without using IB to get a better understanding.
Related
Hello I'm trying to setup a scrollview in the storyboard and followed the following steps to do it:
add a scrollview to the root view.
pin zero spaces to all edges of super view.
add a UIView (contentView) to the above scrollview.
pin zero spaces to all edges of the scrollview add some widgets to
contentView and change the height of the contentView to 2000.
I saw this solution is working on many tutorials I saw but not its not working on me. What am I doing wrong? I use swift.
Can someone explain step by step how do to set up a scrollview in the storyboard?
My constrains:
OK, let's imagine a the following view hierarchy (note, looking at constraints in Interface Builder are easier if you give those views unique names in the "Document" section of the "Identity Inspector"):
To set that up, you'd add the following constraints in IB (I'm justing going to write it in VFL, because it's a very concise way of showing the constraints):
Obviously, define scroll view relative to its superview (the main view, in this example):
H:|[scrollView]|
V:|[scrollView]|
Define, contentView such that
It's width is the same as the main view (==view), and
The scroll view's contentSize will change to fit the size of the contentView. Per TN2154, the constraints between a scrollview and its subviews defines the contentSize of the scroll view, not the relative size of the subviews.
Thus:
H:|[contentView(==view)]|
V:|[contentView]|
Define the layout for three labels such that they're offset within the contentView:
H:|-[label1]-|
H:|-[label2]-|
H:|-[label3]-|
Rather than hardcoding the height of the contentView (and thus the contentSize of the scroll view, instead just define the label's relationship to the vertical height of the contentView, which (because of step 2, above), adjusts the vertical height of the contentSize of the scroll view:
V:|-[label1]-[label2]-[label3]-|
This is all you need to do. I didn't hardcode any widths (the main view has a width automatically, and both the scroll view and, more importantly, the contentView define their widths related to that. But the label widths are inset from the contentView, and the contentView height (and thus the scroll view's contentSize) is inferred from the intrinsic height of the three labels.
The end result is constraints in IB that look like:
FYI, if you want to do some diagnostics, you can click on the view debug button while the app is running on the simulator:
You can see the view (and optionally the constraints) and make sure everything looks ok:
You can also look at the _autolayoutTrace via the (lldb) prompt:
(lldb) po [[UIWindow keyWindow] _autolayoutTrace]
UIWindow:0x7fbbb3617910
| •UIView:0x7fbbb349a840
| | *UIScrollView:0x7fbbb3491c80
| | | *UIView:0x7fbbb348e180
| | | | *UILabel:0x7fbbb348e450'Label'
| | | | *UILabel:0x7fbbb3490670'Label'
| | | | *UILabel:0x7fbbb3490a70'Label'
| | | UIImageView:0x7fbbb34a3eb0
| | | UIImageView:0x7fbbb34a3800
| | *_UILayoutGuide:0x7fbbb349a970
| | *_UILayoutGuide:0x7fbbb349b460
This confirms that there are no conflicting layouts and that there are no ambiguous layouts.
Is there a way to load a UIScrollView in a similar way to how a UITableView is loaded - in other words, only load the visible 'cells'?
For my example I have a large scroll view which can be scrolled in any direction. Inside that are 'cells' which I add to the scroll view using code. The cells consist of data gathered from json feeds (one feed per cell). I would like to only load the feeds for the visible cells, and then cache the ones already loaded, so they don't need to be reloaded.
Is there a good method of doing this? Or is there another direction I should be taking to get this result?
A couple of answers have suggested a tiling approach, but I'm not sure that tiling is quite the right approach, since the whole cell needs to be loaded when part of it is visible. Another approach which google hints at is putting a UITableView within a UIScrollView, but I've yet to try this.
——————————----------------------
| | | < a 'cell' row in the scrollview
| - - - -| - - - - - - - - - - |
screen > | | |
| | |
—————————— |
| | < whole of scrollable area
| |
| |
| |
--------------------------------
You are describing "tiling."
Take a look at Apple's sample code - it demonstrates an approach to tiling.
You can use CATiledLayer.
https://stackoverflow.com/questions/tagged/catiledlayer
https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CATiledLayer_class/Introduction/Introduction.html
All,
I have a regular view controller with several buttons on it, but when one of the buttons is pressed it retrieves information that I want to throw right above the buttons.
For the sake of this, imagine a blank view controller with one button at the bottom. When this button is called, it gets X number of items that need to be listed (and available for selection) right above the button.
I tried illustrating it for you here. :X lol. There are three items viewed, but say that 10 items came back - I need to be able to scroll through the list as well.
The question is this: how do I add a scrolling view (possibly table view) inside of my view controller so that this works as explained?
__________________
| |
| |
| item 1 |
| |
| item 2 |
| |
| item 3 |
| |
| |
| (button) |
| |
|________________|
Thanks
You simply add the UITableView as a subview of the view controller and implement the UITableViewDataSource and UITableViewDelegate protocols as usual.
It's not harder than that. Try it and if you get any problems ask another question.
Do you have Scrolling Enabled on Table View ?
I don't think so you need to do anything. TableView will take care of it.
I want to have same segmented control across on all navigation tabs with segment value change delegate in it which refereshes currently selected tab data. . I dont want to create different sengemented control for each tab.
Please guide me. Thanks in advance.
Regards,
Malleswar
You would need to make your UISegmentedControl a peer of the UITabBarController view. So it would look like this:
-------------------
|UISegmentedControl |
|-------------------|
| |
| |
| |
| |
| |
|UITabBarController |
| |
| |
| |
| |
| |
-------------------
The key here is that your UISegmentedControl needs to not be a subview of the UITabBarController view, so I would create a separate UIViewController subclass that owns and lays out the UISegmentedControl and UITabBarController views.
Also, I'd recommend embedding the UISegmentedControl in a UIToolBar. That will look a lot better than placing it on a blank view.
I want to be able to embed a UIWebView into a tableview's cell (grouped style).
The web view is long (longer than the screen), and I want it to display it's full length. So there is no scrolling within the web view itself, just on the table.
------------------------
| a normal table cell |
------------------------
| a normal table cell 2|
------------------------
| a long webview |
| which doesn't scroll|
| within itself |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
------------------------
The web view will have various heights so how can I discover the the height of the webview in order to adjust the height in heightForRowAtIndexPath?
Here's how you could do it, but see my caution below:
You could load the web view, then use a javascript function to determine the height of the content. You could then use [myWebView stringByEvaluatingJavaScriptFromString: ..] to get the height.
Here's the problem. UIWebViews are fairly slow. The table can't present itself until it knows the heights of the rows, because that's how it determines which table cells to fetch. So scrolling your table view will be jerky, because every time you scroll down to a new cell, the height will need to be computed.
There are two approaches you can take:
1) Don't use a UIWebView embedded in a UITableCell. Instead use a UILabel and determine its height using some of the NSString convenience methods for doing this.
2) Use a UIWebView for the entire table. You can very closely simulate a tableview by doing this, and you will get the UI you need. To handle things like clicks, use the URL loading hooks provided by UIWebViewDelegate.