Keep a UIView or UIViewController on top of all others - ios

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

Related

iOS UINavigationController-like behaviour in a partial screen area (2016)

(I have read other questions and answers on this topic, but most are very old and do not relate to iOS 9 or 10.)
The app design calls for the top half of the display to always contain the same content. (An image being edited by the user.)
The bottom half of the display needs a UITableView. When a UITableViewCell is tapped, the bottom section needs to transition to a new UIViewController with slide-on animation, similar to how UINavigationController push segues work.
Problem: only the bottom view needs to transition to the new view controller(s), and back again. The upper half of the view hierarchy needs to remain unaffected. For this reason, I can't place everything inside a UINavigationController, and I can't have a UINavigationBar at the top of the screen.
Question: what approach should I take in such a situation, where I need only one UIView hierarchy to transition in push-segue fashion, but not anything else? Thanks.
Edited with Solution
Solution follows, for those following along at home.
Yes, you can actually use a UINavigationController for the bottom half.
If you are using Storyboards, the easiest way to do this is to use a container view for each part of the screen which you then can embed a UIViewController in for the top part and a UINavigationController in for the bottom part. If you are doing this programmatically, just add the view controllers as child view controllers to your app's initial view controller (see this answer for more info) which is essentially what the Storyboard will do for you automatically when using a container view.
As a child view controller, the UINavigationController will act independently from the top UIViewController and should behave as expected.
I recommend the programatic approach for the following reasons:
It helps you understand the inner workings of child/parent view controllers much better which will likely save you a significant amount of debugging time down the line.
It makes adding/removing/swapping child view controllers as simple as a few lines of code. Trying to do this with Storyboards is notoriously hacky and cumbersome.
It's much easier to keep track of changes using GIT (most mid-size/larger companies actually prohibit Storyboards for this very reason)
If you want change in part of the screen you can use container view. For details refer Swift - How to link two view controllers into one container view and switch between them using segmented control?
You can use multiple view in one view controller and can give animation like push or pop to show or hide it.
Second approach is you can use Container View which will give exact effect like navigation stack.

Display new iOS UIView everywhere in existing app [duplicate]

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

App structure: UIView vs. UIViewController in a paging interface

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.

What’s a good way to create an overlay view that would stay on top?

I’d like to create a small overlay view that would float on top of all the others. I need the view to accept touches and I need it to stay in place even during transitions between the underlying views. What I have tried so far:
Standalone view inserted into the key UIWindow. The obvious downside is that the view is not attached to any view controller, which means handling (at least?) rotation events by hand.
UIViewController containment, have a “root” view controller that would contain the floating view and all navigation would be done underneath it. This is very much a “first-class-citizen” solution, but presenting a modal view controller overlaps the floating view.
Second UIWindow with a root view controller containing the floating view. This goes against Apple recommendations and I had some trouble filtering which events should go to which window.
Does anyone have a working solution that doesn’t require too much brittle hacking?
In the end I have followed Jonathan’s suggestion and implemented the overlay as a separate view inserted into the key window. The view has an associated controller object (a subclass of NSObject, not UIViewController), and this controller takes care of the rotation logic. That way the view implementing the actual overlay object doesn’t need to care about rotation events at all.

Segue always loads new instance of view

I'm executing a segue like so;
[self performSegueWithIdentifier:#"showSecondView" sender:self];
But the behavior is that it will always "load" the new view rather than show the existing view if it was already loaded.
My question is, how can I keep a view in memory once I've loaded it, so that future segue calls will simply "show" the existing view?
Thanks
EDIT:
Here is my user interface design. It's essentially a custom side tabbar view controller with a UIView (the big gray block) where all of the subviews are placed.
The short answer is that iOS isn't well suited for that, but you might be able to do so. It depends.
The question is how is that view's controller represented in the view controller hierarchy. The standard options are pushViewController (a push segue) or presentViewController (a modal segue). You might be able to do a custom segue that takes advantage of view controller containment (see WWDC 2011 session 102), but I'd be surprised if that would be something you'd want to pursue. Usually when you hear people talking about the frustration of creating new views is a result of their wanting to return to some main view, but neglecting to popToRootViewController and instead having a segue back to that root scene.
A wholly theoretical (and probably impractical) answer that might come up is to use a singleton and do some slight of hand to transition views, but after watching WWDC 2011 session 102 on view controller containment in which they belabor the importance of keeping one's view hierarchy synchronized with the view controller hierarchy, so I don't think that makes sense.
I might be able to make a more meaningful suggestion if I understood your desired user interface. For 99% of apps, they are geared around pushing/popping views, presenting/dismissing modal views, or using some container (e.g. a tab bar container or some custom container) for jumping between sibling views. What is your user interface flow?

Resources