How to have the same subView in different ViewControllers in iOS? - ios

I have 1 subView that should be visible in two different View Controllers in my app (it is a main button in my app with a badge that shows new messages and other relevant information to the user).
What is the best way to achieve this?
Do I have to duplicate the subView in both View Controllers?

UIView's addSubview
addSubview:
Adds a view to the end of the receiver’s list of subviews.
(void)addSubview:(UIView *)view
Parameters
view
The view to be added. After being added, this view appears on top of any other subviews.
Discussion
This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview.
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.
So don't try to do that .

You should simply have two instances of the view that look the same and have them in the same location.
You might want to have central creation method (that also updates all buttons) and target for this button.

Create Your SubView`s CustomView And respectively add the view to your view controllers ,then save the information with NSUserdefualts in one viewController and get it from another ViewController.

Related

Difference between addChildViewController and addSubview?

Both the methods add the view as child of parentview and view can receive events. When to use which one?
It all depends on how you want to manage the new subview. If you want the new subview to be managed by the current view's view controller (e.g. you're adding something simple like a few UILabel objects), you simply call addSubview. If, on the other hand, the new subview has its own view controller (i.e. it's sufficiently complicated collection of views, with rich functionality, that you want to encapsulate all of this complexity with its own controller to manage everything this new subview does) then you call addChildViewController to add the new view controller, but then call addSubview, too.
So, note that addChildViewController, itself, does nothing with the views. You generally immediately follow it with calls that add its view, too, e.g. here is a slightly clarified example from the Implementing a Custom Container View Controller section of the View Controller Programming Guide for iOS:
[self addChildViewController:childViewController]; // add subview's view controller
childViewController.view.frame = ... // specify where you want the new subview
[self.view addSubview:childViewController.view]; // now you can add the child view controller's view
[childViewController didMoveToParentViewController:self]; // now tell the child view controller that the adding of it and its views is all done
So, it's not a question of addSubview vs addChildViewController, but rather addSubview vs addChildViewController+addSubview. If you call addChildViewController, you're doing so with the intent of calling addSubview for its view at some point.
Frankly, this question of addSubview vs. addChildViewController+addSubview is rarely how we think about this. A more logical way of thinking of this is determine whether this new view has its own view controller. If it does, you perform the addChildViewController sequence of calls. If not, you just call addSubview.
For a good introduction to view controller containment (e.g. the rationale for that API, the importance of keeping the view hierarchy synchronized with the view controller hierarchy, etc.), see WWDC 2011 video Implementing UIViewController Containment.
They are very different. addChildViewController associates a view controller with a parent container view controller, while addSubview adds a view to the view hierarchy of the view it is being added to. In the former case, the new child view controller will be responsible for handling events when it is the selected view controller of its parent. Think of a tab bar controller--each tab has its own associated "child" view controller that displays its view within the parent tab bar controller's content area and handles any user interaction within that view when its corresponding tab is selected in the tab bar. You should only use addChildViewController when you have a custom container view and want to add a new view controller to its childViewControllers property. If you just want to add a new view to the view hierarchy that can receive events, which is what it kind of sounds like, addSubview is the way to go. "Implementing a Container View Controller" section explains what addChildViewController is for.
addChildViewController is method in UIViewController class and
addSubview is in UIView class
Both have entirely different behavior.
addChildViewController just puts a view controller in front of the current one. You have to manage the flow of controllers. This method is only intended to be called by an implementation of a custom container view controller.
addSubview adds another view as sub view to the view of that object.
Knowing that MVC means Model-View-Controller:
If you only intend to add the view, then use addSubview. e.g. adding a label, button.
However if you intend to a d view + controller then you must use addChildViewController to add its controller and ALSO addSubView to add its view. e.g. adding another viewController, tableViewController.
In addition:
There are two categories of events that are forwarded to child view controllers:
1- Appearance Methods:
- viewWillAppear:
- viewDidAppear:
- viewWillDisappear:
- viewDidDisappear:
2- Rotation Methods:
- willRotateToInterfaceOrientation:duration:
- willAnimateRotationToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation:
An example of where you would run into an issue if you don't do such is here
For more information I strongly recommend to see answers on this question.
Available from iOS 5, the addChildViewController:
- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);
method let you add any view controller as a child to some other view controller, but first it removes any parent from the childController and than add it as a child view controller to the specified controller.
The child controller is nothing but an instance of UIViewController and thus it will provide the functionality of view controller (i.e it will receive the events like -(void)viewWillAppear, -(void)viewWillDisappear, etc as a normal UIViewController does).
On the other hand
- (void)addSubview:(UIView *)view;
addSubview: will add any view as subview on any other view.
It's not the choice which to use when rather it's the type which asks to use specific method.
For Instance -
If you have an instance of UIViewController than you will definitely use addChildViewController: (also you can use presentModalViewController, pushViewController) and if you have an instance of UIView than definitely you have to use addSubview.
Note : You can also add view controller's view as a subview to any other view as well.
Based on some test, I found that: If child view controller is not added to parent view controller (supposing the parent view controller is under the root view controller), only child view controller's view is added to parent view controller's view, then:
the sub view controller can still receive messages directly related to view, such as - viewWillAppear:, - viewWillLayoutSubviews, etc.
But
the sub view can not receive some system messages, such as - willRotateToInterfaceOrientation:duration:
I can't give the messages list now, however.
addChildViewController is used to prevent the added sub view controller from releasing, in other word, the parent view controller will hold a strong reference to the sub view controller.

Why can't I assign a UIView to self.view?

This might be a stupid question, but I'll shoot.
I made a little test project to test out a concept I had for a sliding view controller type of thing. I naively assumed I could create a UIView (let's call it peekView) with an outlet in a controller, and call something like [slidingControllerSlideFrom:self.view] from any visible view controller, the implementation of such being:
- (void)slidingControllerSlideFrom(UIView*)controllersMainView
{
// push side controller to top of navigation stack
self.peekView = controllersMainView;
// sliding animation
}
But there is no effect. No crash, no warning, no change of view in the pushed controller.
Of course, the pushed controller crashes when trying to add self's view as a subview, but assigning it to a predefined UIView just results in nothing.
So, why? And if a mere 'why' is not enough of a question- what happens when I try to assign one controller's view another controller's subview, and what was the reason for designing UIKit where you cannot set views from self.view?
To do that you have two options:
1 - If the controller in the peekView is always the same one in a given scene, use a "Container View". Those are explained here. Basically, they allow you to add a view in your scene that is managed by another controller.
2 - If the controller in the peekView depends on different conditions, you will have to create something similar to a custom tabbarcontroller. That means that you instantiate the controller that you need, add it's view as a subview of peekView (not assign the controller's view to the peekView itself) and then use didmovetoparentviewcontroller to notify the child controller. This question might help.
UPDATE:
Just saw your comment, so let me answer what you actually asked: The peekview property is actually just a reference to the real UIView you placed in the screen. When you do this:
self.peekView = controllersMainView;
You are changing the reference, but no the view object itself. That's why you are not seeing any changes. There are ways of adding a new view to the controller from code, but it is much simpler to simply use addSubview to add your controllers view to a UIView that is already in the controller.
Check out the discussion here: subView Slide up from bottom of the screen
and here: SubView slide in animation, iphone
Hopefully that gives you a bit of framework on how to approach this task!

iOS - relations between views

I'm just learning the iOS, so my question is very basic... I've read a lot about organizing subviews in the application, but there are so many things there, that I would like to ask you if I've understood it well...
The main part of the app is a window. ViewController manages only one view. In a window I can set the rootViewController. This controller manages the view during entire application workflow. Next I can create some subviews, connect these subviews to the main view (parent) using outlets, and the when instatiating rootViewController I can add my subviews by :addSubview method. Am I right more or less?
And one question more... Should each subview be managed by a dedicated ViewController (then, the parent has outlets to these controllers) or I can change the subviews state directly from parent ViewController?
And short example:
I would like to create an iPad app which has (both visible at a time):
- at the top: short form and button (user enters some data and clicks "Save" button)
- at the bottom: a table displaying provided values
So:
I can create one main view, and two subviews (for form and table). Each time I add some values table will be refreshed using the parent controller... Does it make sense?
It you see that I understand something wrong, please tell me what should I read about.
Thanks for patience.
iOS follows MVC pattern.
The controller class is a manager which binds data to the view. So you can have separate classes for your view and data.
Your understanding is right. To achieve the things you have mentioned,
Create a subclass of UIViewController.
Add two subviews to it (TableView and Button). This could be done using xib or programmatically
Add the delegate methods of your tableview inside your controller class and set tableview's delegate as your controller class.
Add the event for button.
.
rootViewController is the starting point for your application and you can create more viewController and add subviews on the viewController depending on your needs for application.
I would like to create an iPad app which has (both visible at a time): - at the top: short form and button (user enters some data and clicks "Save" button) - at the bottom: a table displaying provided values
you can create UITableView & UIButton as subView to the UiViewController(will be Owner of the subviews) or any other subviews like labels,textfields etc.
The subviews are connected to the files owner that is the viewcontroller..not the parentview.

Can a view be added to multiple other views safely, if so what does removeFromSuperView: do in that case?

I am wondering what happens if a single instance of a UIView object gets added as a subview of multiple other views simultaneously.
If UIView:removeFromSubview: gets called then does it get removed from all superviews or just the currently displayed one?
For background:
I have a status-bar like view object that needs to be displayed within several different other views (each other view is managed by its own view controller).
[i.e. a) the user is in one view, b) something happens to make the status-bar-like view appear, c) the user switches to another view d)the status bar is still visible in the new view e) the status bar expires after a time and disappears from site. And so on]
Initially I implemented this by adding/removing it as required as a subview of the window, and this was managed by a singleton.
However due to some complications with some animations I have instead added it as a subview of each of the main view's for each of the view controllers.
Note that there are not multiple copies
When the view needs to be removed I am calling its removeFromSuperview:, and everything is all working perfectly.
However I am wondering what the situation is regarding the removal of the view, is it being fully removed or is there something else I need to do?
For example the view might get added to N view controller's views by calling addSubview as required (it will only get added to each view controller if that view controller actually launches)
However when it is being removed I am only calling removeFromSuperview: for the view of currently loaded view controller, not all view controllers it might have been added to.
Next time I navigate to one of these other view controllers it displays fine without the view being there, even though I didn't explicitly call removeFromSuperView.
As I said everything is working as it is, however at the back of my mind I feel there might be something missing?
Hope this was understandable.
You can only have it added to one view. Documentation is your friend!
(void)addSubview:(UIView *)view:
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.
From my point of view, having to add a same view to different parent views (and more important, from different view controllers) is an indication that something is wrong on the design...
However, if you really (really) need so, I had always thought that a view instance could have one and only one parent view... Moreover, you can access it by [myView superview] message, which gives you a UIView instance instead of an array... It may auto remove from its old parent before adding to a new superview?
About the design, what about creating it each time you need a new one and have a singleton to manage their status/logic?
Good luck with that!

Using bringSubviewToFront in Ipad scrollview

In my Ipad app, I have a split view in which the detail view is a scroll view...
I have 3 subviews to the scrollview which are tableviews...
How do I use - (void)bringSubviewToFront:(UIView *)view to bring one of the subviews of the scrollview to the front when an action is performed? (since Views are "stacked" in the order they're added with the last one on top). Should I write the code in the subview or in the detailViewController and how do I call it?
You write the code in the controller.
The controller should have access to the table views through IBOutlet properties. Or, if you didn't set them up using a nib, the controller should have been the one to create them.
If a button tap, for example, is responsible for showing a particular table view, the button's action handler method is where you call the bringSubviewToFront: method.
HOWEVER: It sounds like you have three table views on top of each other and are using bringSubviewToFront: to show the current one, and they are all inside a UIScrollView.
Each UITableView contains a UIScrollView. Don't put a scrollview inside a scrollview, they will fight over tracking touches and things will get weird. Just put the three table views inside a plain UIView.
Instead of bringSubviewToFront:, you ought to consider hiding the inactive views (call setHidden:). That way, the hidden views won't be considered part of the responder chain (won't get sent events).

Resources