How to create a custom UIViewController transition animation? - iphone

This question seems to get asked a lot but I have never found a definitive answer as to whether or not it's possible to have custom transitions the same way UIKit does.
I know you can do tricks like take a screenshot of the current view and the upcoming view, and then animate those while you change view controllers under the animation. However, this takes quite a bit of memory, as you have basically 2 full extra screens worth of drawing (because of the screenshots).
I'm looking for a more elegant way of presenting view controllers with a custom animation. Or, is there a more memory-efficient way of doing the above approach?

There are several ways to accomplish this, depending on how you want to transition, whether your controllers are embedded in a container controller, etc. In the simplest case, where you have a single controller, and you want to transition to another controller, you can do it with the following steps:
instantiate the new controller (lets call it B, and the original one A)
add B's view as a subview of the window (gotten from self.view.window)
set B's frame to be off screen in which ever direction you want or make its alpha 0, or make it have zero size, depending on what kind of transition you want.
do what ever transition you want with animateWithDuration:animations:completion:
remove A's view (in the completion block)
in the completion block, make B the root view controller of the window

Essentially you're having the system automatically retain and release, along with do whatever is happening below the calls rdelmar's answer outlined. Transitioning a view controller is just animating a view while having the system keep your controller in memory.
But, to answer more of your questions, UIView animations create duplicates and cache the images, too. (Btw, the system cache doesn't unload its memory, so avoid UIImage imageNamed.
You will probably want to code it yourself using a timer if you want efficiency, and drum up all the graphics tricks you can think of.
And never, ever trust iOS to work the same way it did the last version. Everything I said is subject to being wrong the same way iOS 6 broke retain on annotating, and the manuals stated iOS 3 animations will become obsolete (and are now replaced instead?) gah, just saying be careful with efficiency, it may be broken or updated in the somewhat distant future if you try it.

Related

Iphone - Drawing into a view : philosophy and interactions

I've understood that I need to subclass a UIView t be able to draw inside it.
The thing I don't understand yet, is the philosophy of the way i must be done...
Let's say I have a view controller, and depending on context, I may want to draw a line into one of the subviews it manages, or a circle, or a rect, or a processed graphic. Or lets say two points that are moving inside a view into a defined rect and that display a bigger point when they are close.
How may I subclass and define the subview to make it able to do this only into its drawRect method ?
How does the controller, that manages more than this simple UIView (let's imagine you have a view controller that manages a view inside which there are many other view, and you want to make some drawings in two of them), and that knows what is needed to be drawn into the correct view (it's a controller, isn't it ?), may interact with the views ? And when the drawing is done, how may the views interact with the controller ?
I've read many doc about drawings (apple, web, forums, tutorials, ...), but I still can't touch the philosophy of the way this must be done.
it's very simple. Make a new class, OliverView, which is a UIView. (ie, it is a subclass of UIView.) In that view, make it draw stuff in a fancy way, inside drawRect.
Now make a UIViewController, called OliverVC. In storyboard put an OliverView inside OliverVC. (beginner explanation of how to do that).
In the OliverView, have properties "hours", "minutes", "seconds".
Now, in OliverView - in the drawRect - have a fancy way to display those values. (Pie chart, glowing letters, animation - whatever you want.)
Now, up in OliverVC, do some calculations to determine the time in Zimbabwe, for example.
Once you want a time displayed, simply set those properties in OliverView - - and you are done.
Your colleague could be programming the OliverView. You need know nothing about how she is going to display the time. Conversely, your colleague need know nothing about your calculations in OliverVC..
So, it's simpleL One part has the job of displaying the data. One part has the job of coming up with the data (doing whatever sort of calculation is relevant in the app).
It's the only architecture possible in a "real time" screen device where the views can and do change at any time.
In answer to your question below: you've forgotten that quite simply, if you have a button that would be a whole separate element. (Perhaps sitting "on top of" the OliverView.) So, it's easy!
The -drawRect method in your UIView subclass defines the onscreen appearance of the view. All drawing is done in -drawRect. Your UIViewController calls methods on its UIView to tell it to draw something differently or to perform some other action.
The UIViewController manages everything to do with the view that is not inherently associated with the drawing of the content. Data associated with the view is often stored in the controller.

UIView changes when iphone application starts from background

My iphone application has a user form under UIViewController.
When I out of application (go to background mode) and start application again some of my UIView changes its positions and sizes. (These UIViews depend on keyboard position)
Definately somewhere is my fault.
I try to figure what is going on when application starts again from background and where the UIView changes can be done.
May be you can suggest any links to read.
Thank you.
The UIViewController's viewDidLoad and viewWillAppear methods get called every time the view is dumped from memory, something that commonly happens when the app goes into the background. Depending on your code, it's possible that you're storing some position data that's not getting cleared. If that's the case, you can either:
Change your code to better fit the Model-View-Controller pattern so that the positioning code and variables are all in the controller, and you appropriately clean things up in its 'viewWillDisappearandviewDidUnload` methods (the better way), or
Clear out whatever remnants are hanging around in your application delegate's applicationWillEnterBackground method.

Code design question using UIViewControllers (drawing PDFs page by page) - best practice?

I have written a little PDF viewer which is supposed to show PDFs page by page to reduce memory usage.
It consists of a PdfViewController which shows a specific page of the PDF (using UIScrollView, CATiledLayer).
Now the (maybe stupid) question is: if I want to show the next page (using a swipe gesture ot whatever), how would I do that? Should my controller handle it and update its views (which is a horror becaue CATiledLayer seems to crash as soon as you look at it :-)), or should there be an "outer" controller which generates a new PdfViewController for every page flip (the more flexible aproach)?
What is the best practice in these situations? Looking at UINavigationController, you're supposed to push a new UIViewController for every level. But there, all controllers being pushed may be different. In my case, all pages are using the same controller.
You likely shouldn't use the UINavigationController for that. In general, the UINavController should be used for drill-down operations, where you have a limited set of items to be pushed.
In your case, I think the best option is to use a large UIScrollView which will take care of the pagination and then just create a new UIView with the CATiledlayer inside.
I created for my app Quicklytics a PagedViewController class that does most of that for you. You basically create a PageDataSource that creates the UIViews for each page, and handle it over to the control. You may not use this exactly as is on your code, but it'll give you a good idea on where to go:
https://github.com/escoz/monotouch-controls/blob/master/UICatalog/PagedViewController.cs
Hope this helps you.
Here are two useful resources
Fast and Lean PDF Viewer for iPhone / iPad / iOs - tips and hints? collects a whole lot of information on displaying pdfs.
https://github.com/vfr/Reader a basic pdf reader for ios that does what you are trying to do.
In terms of whether to use nested UIViewControllers I would recommend against it, however if you do you should be aware that they will not handle rotation very well (I don't think they receive orientation change events) as well as viewDidAppear and other view lifecycle events, also make sure only to display modal view controllers from the root view controller otherwise they won't show properly (I had issues with them appearing in the wrong orientation in landscape, or in the wrong position).
In the app I built I used one UIViewController to manage the display of the pdf and I subclassed NSObject for any other "sub" controllers to make it more manageable. For example I had vertical scrolling as well as horizontal scrolling of pdf pages. My first attempt used nested UIViewControllers however I had issues with orientation till I rebuilt using controllers subclassed from NSObject for managing vertical slides.

What's the correct way to represent a linear process in CocoaTouch (UIKit)?

I need to represent a linear process (think wizard) in an iPad app.
In principle I could use a UINavigationController and just keep pushing new controllers for each step of the process. But this seems rather inefficient since the process I'm modeling has no notion of navigating backwards so all previous views would pointlessly stay around and use up resources.
At the moment I keep adding and removing a subview to one "master" viewcontroller and basically swapping out the contents. This works but feels rather clunky and I hope there is some nicer way to achieve this.
Additionally there needs to be an animated transition between the views. (I have this working at the moment via beginAnimations / commitAnimations)
UPDATE:
To clarify my question: I'm aware that wizards usually have a back button. That's not what I'm building here.
The process that has to be shown possibly has a lot of steps (up to around 30-40 in some cases probably) so I really don't want to have 39 obsolete view controllers taking up ram.
Could you set the backBarButtonItem of each view controller's navigationItem to nil so that you don't show a back button?
You can extend uinavigationcontrollerdelegate and check every push event the current stack size. Then you can replace with a new reduced array that contains only the desired view controllers. By the way, if you implement a good memory management and release every resource on viewDidDisappear, i'm quite sure that it's not a matter for the os to manage a huge number of "empty" view controllers.
Hope it helps

iPhone app views logic

I have an iPhone app in development that requires three slides (views). The problem is, since I'm kinda new to this, I'm not sure what's the most logical way to approach this situation.
I was going to use a UINavigationController, but then I noticed that the UINavigationController is meant for hierarchical content, which means that it starts with a root controller which has the lowest level, and then views go child to child. But in my scenario, I have the main/root controller/view in the middle; and you can go to the left or right one, which would represent the middle one's children.
I could set the left view to be the root one, and quickly jump to the second/middle one; but this would be sort of a "hack" since I'm lying myself. Should I do that, or use a UITabBarController (haven't read too much about it), or something else?
Note that none of them will have their nav bar displayed since I want the navigation to be made through swipes.
Thanks!
You might want to try using the UIScroll in a paged mode and laying your views out on that (similar to how Photos works on the phone).