I have a weird question. Wasn't able to find a solution via search neither in SO nor via google.
I have a UIView in my UIViewController which is lead by a storyboard.
This UIView is set, via Interface Builder, to hidden.
Based on certain logics at some point i need to reveal this UIView.
Pretty easy: myView.isHidden = false
problem is that each time my UIViewController loads, it overrides whatever has happened before -such as un-hiding the view- and set the view to hidden again.
Is there a smart way to permanently hide or should I go for UserDefaults storing the value and loading it in ViewWillAppear each time?
Thanks for any possible suggestion.
note: I'm coding in Swift3 syntax
*******************EDIT*******************
To make it more clear:
I'm have a bunch of custom pop-ups which sits on a dedicated storyboard file. Each of the pop-ups has a UIViewController.
These popups are basically achievements popups. They have 3 stars, all of them hidden by default (via IB properties on the 3 UIImageView that they holds).
Along the app, if the user reach a certain kind of achievement, I'll be calling the related UIViewController from that storyboard file and showing (un-hiding) the related achieved star. Just like that.
Main VC:
let viewController = UIStoryboard(name: "AchievementsPopUp", bundle: nil).instantiateViewController(withIdentifier: "Category1PopUp")
viewController.modalPresentationStyle = .overCurrentContext
self.present(viewController, animated: true, completion: nil)
On the related class file, I'm un-hiding via code the star and presenting to the user. Once the user dismiss the popupVC going back to the main one, the "un-hide" property is lost for that UIImageView.
I've solved using a property on UserDefaults which works pretty well.
The problem is that I had to create 15 different properties (5 screens with 3 stars each) and manage the related code which turned to be a little messy :-)
If there are smarter solutions I'll be happy to implement!
You should take a look at Apple's documentation for Preserving and Restoring State.
The preservation and restoration process is mostly automatic, but you need to tell iOS which parts of your app to preserve. The steps for preserving your app’s view controllers are as follows:
(Required) Assign restoration identifiers to the view controllers whose configuration you want to preserve; see Tagging View Controllers for Preservation.
(Required) Tell iOS how to create or locate new view controller objects at launch time; see Restoring View Controllers at Launch Time.
(Optional) For each view controller, store any specific configuration data needed to return that view controller to its original configuration; see Encoding and Decoding Your View Controller’s State.
Related
So I am working on an app and am finally getting to a point where I am starting to build actual modules instead of playgrounds and utility apps for tests. So I really want to do this right since I am jumping into the real deal right now. I was hoping to get advice that will help me accomplish my goals for the apps "flow" without me hacking something together that will come back to bite me later.
So imagine I have a home screen(a single view controller) that can branch to multiple storyboards. The mechanism I want to trigger transitions is the user grabbing an image on the home screen with their finger, and flicking it off the screen. When the image is no longer on screen, I'd like to transition to a storyboard that corresponds to that image. For instance, the user might flick the "settings" image to open a settings panel.
[home storyboard] -- [user flicks image off screen] --> [alternate storyboard]
I have already accomplished this kind of, but with the way I am doing it now I am unsure how to be able to navigate back from the second storyboard back to the home storyboard. It also seems unclean and hacky to me.
Right now it is set up as such:
Home is its own storyboard - main.storyboard
Home contains one simple viewcontroller
Alt is another storyboard - alt.storyboard
Alt contains a navigationcontroller
How can I facilitate things such that Alt's navigation controller will recognize that it was just in the Home storyboard, so that it will provide a "back" button for navigating back home?
Or, if anyone has any advice as to how I might accomplish this in a neater way, I would greatly appreciate it. I want each "module" (ie alt.storyboard's contents) to be in different storyboards for organizational sake.
Here is the code I use to seque to my second storyboard:
if !(recognizer.view!.window == nil) {
print("object left window")
let viewController: UIViewController = (self.storyboard?.instantiateViewControllerWithIdentifier("Alt"))! as UIViewController
self.presentViewController(viewController, animated: true, completion: nil)
}
Thanks so much for taking the time to check this out, let me know if I have not been clear enough.
you could put the main viewcontroller (from Home storyboard) itself into a navigation controller and simply push the initial viewcontroller from the storyboard you want to reach (in your example Alt storyboard) with a custom transition. so the viewcontrollers from all the other storyboards except of Home should not be embedded in a navigation controller!
I'm working on replacing UINavigationControllers and other iOS standard UI classes with https://github.com/CosmicMind/Material and am stuck with NavigationBarViewController in particular. I know that under the hood it uses parent/child controller setup to present new view controllers on itself but I can't figure out how can I have just basic navigation VC push onto the stack with a back button on the left to go back. Going through the source code of NavigationBarViewController doesn't seem like there is a way to do it. Is it possible to do it with NavigationBarViewController?
To transition the mainViewController, which is the body of the NavigationBarViewController, you can use the
transitionFromMainViewController
method. It supports animation options, though, not the MoveIn or Push animation.
In order to do that, you need to use the transition method that is available in the MaterialAnimation API.
Example:
let vc: HashtagListViewController = HashtagListViewController()
vc.view.layer.addAnimation(MaterialAnimation.transition(.MoveIn, direction: .Right), forKey: kCATransitionFromRight)
navigationBarViewController?.transitionFromMainViewController(vc)
Basically what you are doing is tapping into the transition animation for the UIViewController.view.layer.
If you do not want to go to that effort, the
transitionFromMainViewController
offers some nice out of the box animations that you can use.
In a future version of Material, there will be an entire NavigationViewController Stack that will do all that you are asking.
Update
In Material 1.36.0, there are two new classes, NavigationBar and NavigationController. NavigationController is a subclass of UINavigationController, so all the features for pushing and popping UIViewControllers on the stack of items is the same, while getting the ability to customize the controller's look and feel with ease.
The example App project shows how to use this.
We are building a data acquisition app that allows the user to enter other view controllers (preferences screen, log screen) brought forth by
[self presentViewController:secondary_view animated:YES completion: nil].
When certain data arrives, we want to shut down all of these secondary views summarily. We are using
[self dismissViewControllerAnimated:false completion: nil];
to do this. What we find, though, is that if the data comes in while the new view is sliding into place (not done animating), then the dismiss command has no effect, and the secondary view is still there, and in fact the app gets confused about its own state in a way that makes it appear to "hang."
Is there a better (more reliable) way to make sure that all presented view controllers are dismissed, even if they are currently animating?
My recommendation would be to present the scene using Interface Builder (storyboards) and set the Segue Identifier to a certain string with the type of presenting you're wanting done: show, show detail, modally or popover.
(see below)
Once you've done this, you can use the method: prepareForSegueWithIdentifier, where you can be assured the data exchange between the segue.destinationViewController, the View Controller you're sending the data too, and the current View Controller is performed.
(see below)
NOTE
You can perform a segue programmatically using performSegueWithIdentifier: sender:
Also, be sure to remove all the strong references to the data objects that are not being released in your current scenario. Try doing this within the Method above after you've transferred the data to the destination View Controller.
I have been looking for a solution to this for quite some time but I still fail to see what the best solution is:
I am trying to swap view controllers programmatically, without anything in the storyboard, pure swift files.
As far as I see presentViewController() just creates a 'modal' which would cause the previous ViewController to stay in the memory (tested this, deinit never fires for the first controller). The solution I have found is to switch the rootViewController: self.view.window?.rootViewController = ViewController2() -> this fires deinit of the first one.
While this solution would work in theory, I am wondering...
Is there some recommended way or best practice of how to do this programmatically? Or is it really just about changing the viewRootController's value?
How do you structure your app? Do you use one ViewController and you swap views? Or you present other ViewControllers as modals with presentViewController? (I am totally new to this and I can't seem to find any good source; most of the articles deal with storyboard)
Thanks a lot!
EDIT: I will add: my test app is not supposed to have any kind of navigation for different viewcontrollers (no tabs, nor anything like that). It basically works like screen1->screen2->screen3->screen4. If a reset button is pressed, it gets back to screen1. I am purely interested of swapping ViewControllers, nothing else.
1: Changing the main window's root view controller is correct for swapping view controllers.
2: Generally, swapping view controller is not used. You can use a navigation controller that has a root view controller (eg. your main screen) and then push other view controllers as needed. Tab bar view controllers are also very useful.
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html#//apple_ref/doc/uid/TP40011313-CH6-SW1
Hope this helps!
1.
The basic ways are:
navigationController?.popViewControllerAnimated(true)
or just pop to root view
navigationController?.popToRootViewControllerAnimated(true)
pushing can be done similarly
or setting a new stack
navigationController?.setViewControllers([viewController], animated: true)
These are the recommended ways of navigating in code just pick the one appropriate to your specific situation.
The push and pop mechanism is probably the most recommended way of doing general navigation.
Try to always use navigation controllers and only use modal views when appropriate.
Use navigation controllers when navigating through your main views. Modal views can be used as side views or extension to the view presenting that view modally.
Edit:
There are many ways of efficiency navigating through an app. In this particular case pushing and popping the navigation stack is probably the best way to go. But keep in mind that there are Tab bar controllers, collection views and others. At the end of the day The best is to look at your app structure and based on that decide which navigation method is the best for you.
Create a new single-view project (e.g., 'Test')
Within the main storyboard, create two view controllers with titles One and Two - make One the initial view controller
Place the label One within the content of view controller One and label Two within Two
Include the following within the viewDidLoad of TestViewController.m:
// instantiate the new view controller
UIStoryboard *storyboard = self.storyboard;
TestViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"Two"];
// Change the view
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:viewController animated:YES completion:nil];
Save, build, and run.
I consistently get an error of the Storyboard does not contain view controller 'Two' variety. Using breakpoints, I've discovered that the problem is at the instantiation step. Yet the above code is taken directly from Apple's View Controller Programming Guide.
I've combed this site and discovered many people having problems with instantiating view controllers programatically. Any definite solution?
There's no bug here -- you're just writing inappropriate code. The code snippet you've given works fine if you put it in an action and trigger it with a button, a timer, etc. But you're attempting to present another view controller modally before the view controller running the code has even gotten around to displaying its own view.
-viewDidLoad is called when the view controller's view has been loaded from the storyboard or .xib file; it's an opportunity to do any initialization that had to be deferred until the view hierarchy comes into existence. However, the view isn't actually displayed at that point. You need to wait until you get a -viewDidAppear message to know that the view is on screen. So, you can imagine that it doesn't make a lot of sense to try to present some other view controller before the current one has even settled in.
I consistently get an error of the Storyboard does not contain view controller 'Two' variety.
In that case, you haven't properly assigned a storyboard identifier to the view controller. Select view controller "Two" in the storyboard editor and then look at the identity inspector. You need to set the identifier like this:
I've combed this site and discovered many people having problems with
instantiating view controllers programatically. Any definite solution?
Did you also look at the answers to their questions? That's how this site works -- we answer questions not just for the people that are asking them, but also to help others in the future who may have similar questions. Identifying a UIStoryboard is a good example of a question similar to yours with an answer that probably would have helped you.