I have a UIViewController having two parts:
a UIView
a bar having multiple drop down menus arranged horizontally and having thumbnail images at the top
Because second part is little complex I've decided it to be a UIViewController but now I have some concerns:
Because I have drop down menu, menu will exceeds the bounds of the bar. How can I handle it?
Is it a good way to have a UIViewController inside a UIViewController?
How can I implement a drop down menu? As far I know IOS doesn't have drop down menus.
To use a controller within another controller, you employ a custom container view controller.
See Creating Custom Container View Controllers section of the View Controller Programming Guide for iOS.
Also see the appropriate Implementing a Container Controller section of the UIViewController Class Reference.
Also refer to the WWDC 2011 video, Implementing UIViewController Containment
In iOS 6, you can set up storyboards with container views that automatically employ embed segues, saving you from needing to explicitly call addChildViewController and the like, if you're using storyboards. Check out the "container view" object in Interface Builder. If you're going to be changing the child controller, you'll have to employ the API referred to in the above links, but for the configuration of the first child, you can set that up in Interface Builder in iOS 6.
In this case, setting up a controller containment could be the right way. The only limitation is that it works for iOS 5 and greater.
Here, what you have to do:
// add as child VC
[self addChildViewController:_barViewController];
// add it to container view, calls willMoveToParentViewController for us
[_containerView addSubview:_barViewController.view];
// notify it that move is done
[_barViewController didMoveToParentViewController:self];
Here, you can find additional info Containing ViewControllers. Obviosly Apple doc is your friend. In addition, if you search for "uiviewcontroller containment" you can find a lot of tuts out there.
If your app needs to target devices where iOS 5 is not the minimum, you should rely on a UIViewController and two different views.
About drop down menus, in my opinion they don't work so well with touch interfaces. There are some alternatives, for example an instance of the UISegmentedControl class. Here you can read Apple UI design guidelines about segmented controls: http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/UIElementGuidelines/UIElementGuidelines.html#//apple_ref/doc/uid/TP40006556-CH13-SW1. If you explain a little bit more about your desired UI functionality we could offer you a better alternative from the user experience point of view.
If you insist with drop down menus, there are some third party control libraries available out there; for example: http://www.cocoacontrols.com/
Related
I'm new to Swift, so I apologize for my lack of knowledge of almost anything related to Swift.
Right now, I'm developing an app that uses the ARSlidingPanel library, so now there are two ViewControllers present on the screen (Main view, with the dark background, and Panel view, which is the green background). I want to be able to set vars/call functions from the Panel view to the Main view. For example if I click a button in the panel view, I want to display some text in the main view. Right now I've started with using static vars but from my knowledge of Java/Android, I know this is probably not the right way to go. Any tips for a cleaner/more acceptable way of doing things?
There are a few different options here. However, the first thing that comes up to mind is if you really need to use two independent view controllers for the same view?.
One solution would be to use delegates. Write a swift protocol that has has the methods and functionality you want to expose, for example setting up values in the view controller's outlets, then implement the protocol in one view controller. In your other view controller, you can then create a delegate variable of type UIViewController -let delegate: UIViewController - and use that instance of your delegate to modify the view. Here's a guide on this
Even better, you can add view controllers as sub view controllers
of your view, apple provides a good bit of documentation on this, you
can find it
here.
Hope this helps.
I am subclassing UIApplication to intercept and display touches in my TouchDisplay view. I would like to extend the Application, Window, Delegate or Main ViewController in order to keep my TouchDisplay view on top of all other views. As my and most other applications work, views and controllers are added and removed all the time. I figure the correct answer will be able to deal with these additions and removals and stil keep the TouchDisplay view on top.
Thanks for your help,
Joe
Here are a few approaches you could take for this:
If you're targeting iOS 5+ and iPad only, you can make a top-level view controller which has two contained view controllers. The first would be a view controller for your "TouchDisplay" view. The second would be the application's normal root view controller. (i.e. your existing main view controller; you'll need to set definesPresentationContext to YES on this view controller) Since you're writing the container view controller, you can order those two subviews however you like. There is a WWDC 2011 Talk on view controller containment that goes into great detail about this. This is the most "correct" approach IMHO, because it gives you a view controller for your TouchDisplay view, handles rotation and generally plays nice with others. (This only works on iPad, because on iPhone a new modal view always covers the full screen.)
A more straight-forward approach is to simply add your TouchView to your existing top-level UIWindow as a subview with addSubview:. Most applications don't actually remove the top-level view controller or add new top-level ones; they just present other view controllers from it. A view you add in the top-level window will stay above those. Of course, your app may not follow this rule, in which case you might try option #3 instead. This has rotation gotchas (your view will not auto-rotate when the device rotates, so you need to do this yourself.) You could also force your view back to top, say, on a 1-second timer, if you are having issues with other things covering it. This is also not as nice as option #1 because you don't get a UIViewController, just a UIView.
The most extreme approach is that you can create another UIWindow and give it a higher window level, such as UIWindowLevelAlert and put your TouchDisplay view in that. You can then make the window background transparent, and it will stay above your normal app content. There are lots of gotchas here, especially about auto-rotation and which window is the keyWindow (which is why you should use #1 or #2 instead if you can).
After some time I was able to get my app working. I have made an easy to use overlay that shows touch feedback over your existing application.
You can download the project here:
https://github.com/megaplow/FingerTracks/tree/master/FingerTracks
Happy coding,
Joe
There are some great answers relating to when to use a UIViewContoller vs. a UIView. For example here and here.
The general gist is that a UIVIewController should be used to control a full screen of data, because
It is designed to handle rotation. Only one UIViewController should be on the screen at once because only the newest will be notified that the rotation occurred.
To stay true to the MVC paradigm, your business logic should live in a UIViewController, while only display and interaction logic should live in a UIView. Presumably business logic relates to what's on the entire screen.
My question is, given this, how do I structure an app with left-right paging between several top-level views?
I want to create an interface with several UITableViews holding a list of recipes. The user swipes left and right to navigate between lists. There is a common menu on the bottom that stays fixed no matter what.
My initial thought is to use one UIVIewController for the UIScrollView, then add subviews from there.
However I'd really like each list to have its own UIViewController, so it can handle its own rotation, and hold business logic like its own REST methods. It would seem to be a pain to have the top-level UIViewController handle the rotation of a child subview, and it would seem to be a violation of MVC to put the logic anywhere else.
Is there a way to structure an app so that multiple UIViewControllers live inside a UIScrollView, or would it appropriate to use a series of top-level UIViewControllers and UISwipeGestureRecognizer to simulate the paging effect of the UIScrollView?
Thanks.
A couple of thoughts:
If targeting iOS 5 and higher, I'd suggest using a UIPageViewController which is designed for precisely this UI (swiping back and forth between UIViewController instances). You would then have a separate UIViewController for each recipe. In iOS 5, you only have UIPageViewControllerTransitionStylePageCurl transition style, but in iOS 6, you also have UIPageViewControllerTransitionStyleScroll.
For more information, see the Page View Controller section of the View Controller Catalog for iOS.
This is much simpler than writing your own scroll view based solution. If you "roll your own" with a UIScrollView, you'll want to remove instances that have scrolled off screen (by registering as the scroll view's delegate and responding to scrollViewDidScroll) so you don't use up memory unnecessarily.
If you do add child view controllers to your scroll view, don't forget to call the appropriate custom container calls. Specifically, as you add view controllers to your scroll view, make sure you call the following (assuming controller is the child controller and self is the main view controller):
[self addChildViewController:controller];
[self.scrollView addSubview:controller.view];
[controller didMoveToParentViewController:self];
And as you respond to scrollViewDidScroll to remove view controllers that are no longer visible, do the appropriate removal calls, e.g.:
[controller willMoveToParentViewController:nil];
[controller.view removeFromSuperview];
[self removeChildViewController:controller];
For information about why it's important to call these custom container calls, see WWDC 2011 video Implementing UIViewController Containment.
I definitely wouldn't recommend using a UINavigationController, though, because it will keep all of the previous pages in memory.
I believe for the requirements you're talking about you could use a UINavigationController. It will give you the "left-right" paging that you want and you can use a UIViewController for each of your recipes.
Also, I think you want to use a UIScrollView because it lets you perform a "swipe" gesture. If that's the case you could also add a UISwipeGestureRecognizer to your view controllers and every time the gesture is recognized call pushViewController:animated: and popViewControllerAnimated: to perform navigation between your recipes.
This is just and idea.
Hope this helps!
As far as I see, there are 2 good options:
Using a root UINavigationController and push/pop child
ViewControllers depending on the direction of the swipe gesture
(recognized by UISwipeGestureRecognizer, just as you said).
Using a root UIViewController with a UIScrollView and adding the child
viewcontroller views as subviews of the scrollview. To handle
orientation changes, you could pass the orientation-change
UIViewController methods (willRotateToInterfaceOrientation,
didRotateFromInterfaceOrientation) to the child controllers, so they
can handle them.
I hope I helped
Firstly, you should be aware that since iOS 5 it's been possible to include child view controllers inside your main view controller.
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
So it seems to me that a good options would be to have a paged UIScrollView as your main controller, and then to put instances of your child controller onto each page.
Since that could all be a little memory intensive, you should really only have three instances at any one time (one being displayed, and one one either side so that they're ready if the user starts to scroll). The Apple demo project shows you how to configure a scroll view like that:
https://developer.apple.com/library/ios/samplecode/PageControl/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007795
Hope that helps.
I'm writing an app that has two sections like this:
The idea is that on the top half I'm creating a request, and on the bottom I'm displaying the results. As my UIViewController subclass grows and grows I thought it might be a good idea to split that into two UIViewControllers. (So what I'm trying to do is something like a UISplitViewController).
Although I know it's possible programmatically I'd like to put both UIViewControllers in the screen from the Interface Builder so I can manage autolayouts and design there. Dragging and dropping doesn't work there.
Is that possible? And more important - is that a good design or should I stick to the rule "One view controller for one screen"?
You can use a custom container view controller to achieve what you want. See:
WWDC 2011 #102 on UIViewController Containment (Apple developer ID required)
the containment section of the View Controller Programming Guide
the containment section of the UIViewController Reference document
In short, since iOS 5, you no longer have to have a single view controller. Just make sure you call the necessary containment related calls. And iOS 6 makes it easier to design the storyboards for custom containers with the "container view" object.
Apple have stated (WWDC 2012, Evolution of View Controllers, I think) that the "screenful" is no longer appropriate. A view controller should manage a self-contained chunk of functionality.
As of iOS5 you can compose an interface of multiple view controllers using view controller containment (addChildViewController: and so forth). As of iOS6 you can do this in interface builder using containers and containment segues.
You will of course need a view controller to hold your two child view controllers - this will hold a screenful of content, and will usually perform any coordination between the two children.
I have a ViewController (with navigation) that needs to show 7 different content layouts. I want to keep the same background and nav, the only thing that needs to change is the central UIView.
If I have 7 different UIViews on the same xib/storyboard, can I hide the ones I'm not using or will that ding performance?
Using segues won't work either because they make a mess out of my custom navigation and animations.
Is there a better way to accomplish what I am trying to do? Thanks for suggestions
solution
My design is too custom for using view controller containment so I decided to mimic the idea with a custom UIViewController and two UIViews. It's not too bad and it works rather quickly.
You should look into using view controller containment, then you can load your views from separate nib files and still provide your custom navigation and animations from your container view controller.
Note: This is only really supported from iOS 5.
Generally, it's a good idea to unload views that aren't visible, however, if your views aren't using too much memory (and/or cpu time) hiding them when they're not in use should work fine.
View controller containment is probably what you should be doing if each view has its own unique functionality (i.e. view 1 is a map, view 2 shows some about text, view 3 is an image gallery). UITabBar might be useful, but it depends on your app.
The performance hit would depend on your views' contents. If you haven't done so already, invest some time into learning how to use Instruments (apple's diagnostic tool). Watching the video titled "Optimizing App Performance with Instruments" in the developer resources would be a good start.
My design is too custom for using view controller containment so I decided to mimic the idea with a custom UIViewController and two UIViews. It's not too bad and it works rather quickly.