UIScrollView with controls repeating on every page? - objective-c

I have perfectly working UIPageControl. I would like to add paging by swipe, and as I understood, it is done by UIScrollView.
But all tutorials are done with images, I want to have controls (labels, buttons) repeating on every page.
Because UIScrollControl is working the way that it must have set its width * pages count, does it mean, that controls can be placed only in code, not in IB?
Should I place labels and buttons directly on UIScrollView?
Thanks

If you have a View Controller designed using IB with all its buttons and labels, then it is possible to add that View Controller as a subview of your UIScrollView as such:
[scrollView addSubview:controller.view];
scrollView being your UIScrollView and controller being your IB designed View Controller.

You can achieve repeating controls with pagecontroll by using IB by ordering the objects appropriately. Here's what I have:
Drag the UIScrollview to the ViewController and also the drag the Page Controller and other controls also to the ViewController but not onto the UIScrollView. Keep them separate. The objects on the bottom of the IB list of objects shows up at the top of the view stack. (So when you swipe new pages the controls dont move and isn't covered by the UIScrollView) I also group the various controls by group selecting them and then use the "embed with view" menu item so that in IB I have two groups, the controls and the UIScrollView. Makes it neater and easier to manage. As for changing labels, I haven't tried it but I've seen tutorials where you can have iboutlets linked to changing value of pagecontroller and then update the labels in uiscrollview appropriately.

Related

Only subviews added in viewDidLoad automatically resize

I've created a custom subclass of UIViewController that acts like a UINavigationController or a UITabBarController. Let's call it a ToolbarNavController. It has a toolbar at the bottom with controls for the user to move to a different content view.
I have two content views aside from the ToolbarNavController's view. Both are loaded from a nib and have their own controllers. The app starts out showing one of them. A button in the toolbar allows the user to switch between them.
When I add these views as subviews of the ToolbarNavController's views in viewDidLoad, they are correctly resized to fill the area between the status bar and the toolbar without overlap/underlap.
But when I try to lazy load the second view, adding it as a subview for the first time only when the user presses the toolbar button, iOS does not resize the view to account for the toolbar in its parent view, and it underlaps the toolbar which messes up my Autolayout constraints. Also, when I don't add the subview in viewDidLoad, if I put the device in landscape orientation before switching to the second view, it loads with a portrait orientation frame.
Bottom line: When inserting a subview in viewDidLoad, iOS sizes it correctly and manages autorotation for it. When inserting it later, I need to detect orientation set the frame myself. (And for some reason when I do this, autorotation kicks in again).
What is going on?
In viewDidLoad, the view is not yet layout for the resolution and interface orientation, and view properties are as they were in the interface designer. So, if you had a portrait view, that is how the initial properties of the view are set when going into viewDidLoad. When you add your view there, you add it to the XIB view. Later, iOS performs layout on the view hierarchy and thus resizes your inserted view as needed. But when adding your view at a later point, the view hierarchy has already been layout, so it is expected that the new view you are adding is also layout correctly.
Best practice is to calculate the size you need using the size of the view you are inserting into. For example, half the width of the containing view, or third the bounds, etc. This way it is independent on the orientation the interface is in.

UIScrollView longer than VC

I've been working with some UIScrollView objects that are longer than the view controllers they are contained by (this is in storyboard). Right now if I want to move objects that aren't initially shown I have to resize both the view controller and the scroll view. I also have to do this to add new objects to an initially non-displayed area. I know that I can do these things with the dimension inspector, but if I do that I can't tell what the layout looks like.
Is there another way to do this? I haven't been able to find a way to make the scroll view "scroll" inside of storyboard/IB. And it's kind of a pain to do layout this way.

In Interface Builder, how can I add UIViews to a subview that is a part of a custom view I've created?

I am working to create a custom view for an iPhone app I'm creating. This custom view is a Popover dialog which is made up of a UIView which contains two images, a button to close the dialog, a label, and a UIScrollView. This view is named MDPopoverCard. I have these files as a part of my view:
MDPopoverCard.xib - The view as drawn up in Interface Builder.
MDPopoverCard.h - Defines a few IBActions and some other properties
MDPopoverCard.m - Implements some functions defined in the header
This is what it looks like in Interface Builder: http://cl.ly/2B0f2x3s1w1i0K2G0Q1r (sorry, I can't post an image yet as I'm new to stackoverflow)
There are a few properties defined in my .m and .h files that control whether the green button is displayed and what the text of the title label is.
I need to display a number of these dialogs in my app and I'd like to reuse this interface I've designed. I want to be able to add buttons and other form elements into the UIScrollView via Interface Builder. However, I have a problem:
Imagine that I have another view I'm drawing up in Interface Builder. I add a UIView to it and set its class to MDPopoverCard. I then drag a couple UIButton objects into my MDPopoverCard view. Here's an example of what it looks like in Interface Builder:
http://cl.ly/1X090h1t1q3f0i3E0917
This screenshot shows another view (the root view) that I've added my MDPopoverCard to. I've then added two buttons as subviews of MDPopoverCard.
These buttons do get properly nested in Interface Builder. However, when I run my app these buttons are added before any of the items that make up my MDPopoverCard view in the xib file. This means that the buttons are being added behind my popover dialog. That's the first problem.
The second problem is that I want these buttons and form elements to actually be added into the UIScrollView that's contained within the MDPopoverCard view, and not just right into the UIView's subviews array. Is there a way to specify this in Interface Builder? I'd really much rather draw buttons into my UIView and connect them to IBActions via Interface Builder than hand write every instance of these dialogs that I may need to display (several).
Any advice? Is there anything I can do to clarify the question?
Thanks for your help!
Formerly Xcode supported user-defined IB plugins for custom UI elements which you could just drag and drop into the XIBs the same way you do with built-in widgets. As of Xcode 4 this nice feature has been removed. (Thanks a lot, Apple.)
Currently I can only think of a hacky way to achieve what you described. What I would do is the following:
create an IBOutletCollection on your MDPopoverCard, e.g. embeddedControls
link it with every UI element (here: the buttons) you want to go inside the scroll view
implement the awakeFromNib in MDPopoverCard and explicitly reset the superview of all the views in embeddedControls to the scroll view in there
Hope this helps (although I haven't tried).

Why doesn't UIScrollview have an accessibility area in the Interface Builder?

I've noticed that a UIScrollView doesn't have mentioned accessibility area where I can set accessibility label or accessibility. This seems to apply for activity indicators too.
Why does UIVIews, UIButtons and more have this area and not UIScrollView and UIActivityIndicatorView?
Good question - the reason for a scroll view is that Apple don't consider it to be an accessible element.
If you look at the UIAccessibility documentation, you'll find Apple have the following to say on what counts as an 'accessible element':
The only exception to this [a view being accessible] is a view that merely serves as a container for other items that should be accessible. Such a view should implement the UIAccessibilityContainer protocol and set this property to NO.
A UIScrollView is simply a container for subviews, so its isAccessibilityElement property is set to no (hence why you don't see the accessibility options in interface builder).
So basically, when you're using a scroll view the items inside it should be accessible, but not the scroll view itself.
To add more details on UIAutomation accessibility labels for UIScrollView you will have to use the index to the ScrollView to access subviews on the scroll view. Eg :
target.frontMostApp().mainWindow().scrollViews()[0].buttons()["logoutButton"].tap();
NOTE : Assumption is that the "logoutButton" is the accessibility label for the logout button and it is a subview on the scroll view.

Programmatically change subviews from within subview's controller

In my iPhone application I've set up a default, blank view called Main View into which various child subviews will be loaded for different parts of the application. It's the same approach as if I was using a tool bar to switch between subviews. That case, in the MainView controller I could hook IBActions to buttons in the toolbar, so that when a button was pressed, MainView added different subviews to itself.
In my situation, though, I need to tell MainView to change its subview from within the subviews. So here are two sister subviews, each with their own controller and xib, that would be loaded as subviews of MainView:
- StartView
- FormView
In StartView, after some animations and welcome stuff, a button triggers the camera image picker. Once the image picker returns the image, I need to tell MainView to remove StartView and add FormView.
It may be the result of a long day or my newness to iPhone OS but I'm stuck getting my head around the right way to set up my objects/controllers.
You never have more than one view controller active at a time. (The nav and tabbar controllers don't control views, they control other controllers.) In this case, you will have a single controller that has the MainView as its view property. It will add StartView and formView as subviews of MainView.
However, this is not a good design. It will overload the MainView controller by forcing it to juggle many views. It would be better to use a hidden navigation controller or a tabbar. Hierarchies of controllers can create the illusion from the users point of view for almost any interface layout you can imagine. There is no need to create a logical structure that mimics the visual one.
From your description you may only need a single view/view-controller pair: Set the formView controller to open the camera view before it displays the formView. When the camera is dismissed it reverts to the formView automatically. No fuss, no muss.