Is there a way to set (preferably in storyboard IB) an image, which, will serve as the background image for all ViewControllers in the whole storyboard. I don't want to have to add a background image in every ViewController or replicate that in code.
I would could create a UIViewController subclass (e.g. name it DefaultViewController) that sets a specific background color in one of the initialization methods (e.g. viewDidLoad, but don't forget if you override this in a subclass of this class to call it's super method).
Then, let all your view controllers inherit from DefaultViewController
Example code:
class DefaultViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = = UIColor.redColor()
}
}
class SomeViewController: DefaultViewController {
override func viewDidLoad() {
// this call makes the background red, you can also not override this method and it will work too
super.viewDidLoad()
}
}
Related
What I'm trying to do
I'm trying to detect:
when a new UIViewController has entered the screen
when a UIViewController has left the screen
when a UIView has been added to the screen
when a UIView has left the screen
Key Point: I'm trying to detect all these changes from the outside.
Meaning: I don't want to have to respond to these changes from existing funcs inside the classes themselves, I want to be able to observe them from an outside class and react accordingly.
Bonus points: If we don't have to know ANY info about ANY of the UIViews or UIViewControllers beforehand, and we don't have to add ANY code to the views themselves, that would be amazing.
My initial thoughts is these involve KVO and listening to the UIViewController's view's window property and similar things.
You could make a BaseViewController class that inherits from UIViewController and overrides the viewDidAppear(_:) and viewDidDisappear(_:) methods. Within each of those you could post a notification.
Then make all UIViewControllers that you care about inherit from BaseViewController.
You still have to add code to all your ViewControllers, but it would just be an inheritance from a single class.
class BaseViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// viewDidAppear notification
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// viewDidDisappear notification
}
}
Same idea with a BaseView class.
class BaseView: UIView {
override func addSubview(_ view: UIView) {
super.addSubview(view)
// notification
}
override func willRemoveSubview(_ subview: UIView) {
super.willRemoveSubview(subview)
// notification
}
}
I'm building an app where two view controllers share a UIView subclass as the main source of UI. It works perfectly when the app is starting, but if I navigate away from the initial view, and return to it, all of the UI is lost. What do I need to do to preserve the views UI post-navigation?
My app flow is: MainView -> TableView -> DetailView
Just going from Main to Table to Main itself makes the UI vanish.
(rank isn't 10 yet, so here's a link to view: https://gfycat.com/enormousanchoredindochinesetiger)
What I do is load the UI in the UIView class through layoutSubviews, and in the UIViewControllers I set the instantiate the class, UI in the loadViews method by saying view = viewClass. I've tried adding this (view = viewClass) to viewWillAppear() as well, but it does nothing.
I've also tried creating two unique view classes in case instantiating was a problem. It didn't change anything.
ViewController:
override func loadView() {
super.loadView()
view = baseView
view.backgroundColor = .white
self.navigationController?.isNavigationBarHidden = true
requestLaunchData()
setButtonTargets()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.isNavigationBarHidden = true
view = baseView
}
//How I push to the next view
#objc func upcomingButtonTapped() {
let vc = TableViewController()
navigationController?.pushViewController(vc, animated: true)
vc.upcomingLaunches = upcomingLaunches
}
UIView:
class BaseView: UIView {
//Lots of labels and buttons instantiated
override func layoutSubviews() {
super.layoutSubviews()
setUI() //adding subviews
}
//Layout configurations
}
Before it was this structure, I had all the UI (labels, buttons, a map) directly created and configured in each ViewController, which made both massive. But, it also worked.
I solved it after a night's rest.
So here's how you need to use a custom UIView class as your ViewController's view:
class YourView: UIView {
//Create your properties, views, etc.
let exampleView = UIView()
override layoutSubviews(){
super.layoutSubviews()
addSubview(exampleView)
//Add layouts, etc.
}
And then in your ViewController, in either viewDidLoad, or loadViews (like me here):
let customView = YourView()
override func loadView() {
super.loadView()
view = customView //Sets the entire view to all the UI you created in the custom class
}
The FATAL mistake I made was this:
override layoutSubviews(){
super.layoutSubviews()
if let sView = superview { //This gives you frame size and such
sView.addSubview(exampleView)
}
}
This sets the UI's memory to the SuperView, which gets lost the moment you leave that view, because of view = customView. So my controller was rendering view = customView, which was empty, because all the UI was set to the superView which was superseded by customView.
I hope that helps anyone trying to use this same architecture in the future.
I am developing a game where the first View Controller will contain full functionality for the rest of the 30 View Controllers, where the rest of these controllers will be sublass of the first view controller. My plan is to use single storyboard for all 30 view controllers or scenes in my app which will all use the same background image. To give you an idea as to what I'm talking about, I only show 2 scenes in this Drawing.Storyboard image but plan is to have 28 more scenes in this same storyboard.
Drawing.Storyboard
If all 30 scenes in this storyboard will have the same UIView background image, how to handle that. Will I have to add same background image for each view in scene or just add background image to the first scene view and use container view for the rest? Note I have never use container views in the past.
After further research and suggestion by "h44f33z", the following will work without using UIView image in your storyboard.
ViewController A
class ViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Load background image for all views
let bgImageView = UIImageView(frame: UIScreen.main.bounds)
bgImageView.image = UIImage(named: "bg_image")
self.view.addSubview(bgImageView)
}
}
View Controller B
class ViewControllerB: ViewControllerA {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
There is nothing you have to do in ViewController B because it is a subclass of ViewController A. With this setup you can go with as many as possible views as long as view is subclass of the first view controller.
One way to do that, you can just create a parent / base class of UIViewController and add UIImageView to self.view in viewDidLoad()
So, for the all 30 ViewControllers, should extend to that base viewController. It will look similar to this
class StartViewController: BaseViewController
Your base class viewDidLoad will be something like
override func viewDidLoad() {
super.viewDidLoad()
let bgImageView = UIImageView(frame: UIScreen.mainScreen().bounds)
bgImageView.image = UIImage(named: "bg-image")
self.view.addSubview(bgImageView)
}
You can event add more functions or handling in the base class and will be easily used by all 30 child viewControllers
I have created a subclass of UIViewController called LoginController. I have a LoginController.xib file that contains a view controller with a few elements in it. I have set the class of the view controller to LoginController and I have set my Main Interface to LoginController. Upon launching my app, I see my splash screen, followed by a pure black screen. My LoginController class just has the default code like so
class LoginController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
I just created a new xcode project. My results are totally normal. So I guess it's because you are not setting the LoginController.xib as the initial xib to load?
I'm trying to create a custom segue. It doesn't work in the first time. I found a solution afterward by creating a new file extends UIStoryboardSegue and create a method called "perform". It works right now without using prepareSegue in ViewController. I'm copied my previous codes from preparedSegue to "Perform" func in new UIStoryboardSegue file. It print out the message but the delegate doesn't work.
View Controller
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Custom Segue
class CustomSegue: UIStoryboardSegue {
let transitionManager = TransitionManager()
override func perform() {
NSLog("Perform");
let toViewController = self.destinationViewController as UIViewController
toViewController.transitioningDelegate = self.transitionManager
}
}
I placed breakpoint in every func in Transition Manager, none of them execute and stop.
Segue settings:
Problem: TransitioningDelegate is not working
Full sources codes: here
The problem is that your perform implementation doesn't do anything:
override func perform() {
let toViewController = self.destinationViewController as UIViewController
toViewController.transitioningDelegate = self.transitionManager
}
All you do is create a view controller, give it a transitioning delegate, and then throw it away. You do not perform any transition! But that is exactly the job of a segue. It isn't clear what you can possibly be expecting to happen.
If the idea is that this is supposed to be a present (modal) segue, then you should make it a present (modal) segue in the storyboard, specify your custom segue class, and then, in your perform implementation, call super to do the actual presentation:
override func perform() {
let toViewController = self.destinationViewController as UIViewController
toViewController.transitioningDelegate = self.transitionManager
super.perform() // this will work, _if_ you have specified a present (modal) segue
}
Alternatively, your perform could perform the presentation itself, by calling presentViewController:... on the source view controller with the destination view controller as parameter.
But your perform does nothing. Nothing will come of nothing.