Embedding UIViewController view inside another UIViewController - ios

In my app, I have a login-register-forgotpasword wireframe. Each step of the process is implemented in a separate UIViewController, all of them inside the same Storyboard, and transitions between each controller are animated. So far so good.
Now we've changed the design, so all views have the same background elements and a header (not exactly a UINavigationBar), and I don't like the feel of the animation to a view that always looks to be actually the same, but just showing a different form. So I'm considering different approaches to, instead of pushing whole controllers, just showing/hiding its views, but staying in the same controller.-
1) My first try was instantiating the controller which view I want to show, and add it to the current view. Something like.-
- (IBAction)btnRegisterPressed:(id)sender {
_viewHome.hidden = YES;
RegisterController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"registerNewUser"];
[self.view addSubview:controller.view];
}
This one would be perfect, as I'm using static UITableViews for my forms, so as far as I know I'd need a UITableViewController for each one. But it seems IBOutlets and IBActions got broken. Is this approach possible in some way? If so, it's considered a bad practice?
2) My second option is just creating all the views inside one controller, and properly showing/hiding them. This would one be hard to maintain, and chances are I'd have to forget about static UITableViews.
Could anyone give me some advice of which option would be better, or point me to any other possible approach I'm missing?

Your option #1 is not appropriate as written but close to an approach you should probably consider. You can add nest the views of different UIViewControllers however when you do so you should use the methods described in Managing Child View Controllers in a Custom Container so that the parent controller correctly manages its child controllers.

You can use as many tableviews as you want for the same controller. The delegate methods contains the object that fired the method itself.
Following this approach (which i wouldn't recommend) you can probably tag your tableviews and then do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (tableView.tag == 1) {
doStuff;
} else if (tableView.tag == 2) {
doOtherStuff;
}
}

Well, personally, I feel we should keep things simple and straight forward for end user to quickly gel up with your app. Animations plays an important role in this. Tapping on cell of a tableview pushes another table view and there are different UI widgets like chevron that indicates the transition and user is not surprised.
Showing everything on single screen and hiding/unhiding them based on user's action is fine as long as you have proper animation. For instance, you might have seen TableView sections collapsing/expanding on tap.
You need to make a trade off and see what best suits based on your application. Whatever you decide my suggestion would be to add nice animations instead of simple hide/unhide.

Related

Segmented control to toggle through multiple tableviews

What I’m basically trying to is to implement the control segment/tableview as in Mailbox (see it around 2:00: http://www.youtube.com/watch?v=FG-h8pDXfoE&feature=youtu.be&t=2m)
I am using Core Data in one UITableViewController hooked up to a UITableView.
When user toggles the UISegmentedControl, the TableView is reloaded with a different set of NSPredicate, and UITableViewRowAnimationRight/Left, kind of makes it appear that that a different table view slides in and replaces the old one.
As the number of cells increase, the performance of this design decrease dramatically, and it could also look much better.
I can see a few different ways of going about it, but I figured I'd ask you guys for some pointers to head me in the right direction:
What is the best way to have a segmented control to toggle through multiple tableviews? Should these tableviews be connected to the same data source/delegate?
Take a look at this pod: https://github.com/xmartlabs/XLMailBoxContainer. It makes the UI animation among the view controllers. These view controller can extend UITableViewController or any other view controller.
UITableViewCell swipe animation can be accomplished using https://github.com/alikaragoz/MCSwipeTableViewCell.
I hope this could help you!
It really depends how different each of these table views is. If they are quite similar, it's probably easiest to just share the delegate and data source and have some conditional code.
In fact you can just have a single table view, but have different cells / configuration depending on your current context.
Could be as simple as having adding some conditions to
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Another approach would be to use view controller containment. You would create a UITableViewController for each and then have parent view controller with segmented control which swaps child view controller accordingly.
As for the animation and performance, I can't really see any problem. You can get the animations without much effort if you use NSFetchedResultsController, see an example here: https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html.
See SBSegmentedViewController. I wrote it for exactly what you're trying to do.

UITableView inside UIViewController not displaying

I am trying to set up a UITableView inside of a UIViewController. I'm doing this because it allows me to add a top bar with save and cancel buttons. I'm using storyboard and static cells to model the tableview to get input from the user (think of the create new event in Apple's calendar app). I have the view in Xcode, but when running it on my phone or the simulator, the tableview does not display. Here is the simple view in Xcode:
And this is how it displays when running it:
I've read about adding delegates and setting the datasource and such, but really this is all just going to be static cells with text fields, no data being loaded. Why is this happening and what can be done to fix it? Thanks!
#Made2k It looks like you found a solution, but for others who come across this with the same issue, note that you can only use a UITableView with static cells inside of a UITableViewController. This is not a well-documented fact, but apparently only UITableViewController knows how to handle the layout of static cells, whereas a regular UIViewController just needs to implement the UITableViewDelegate and UITableViewDataSource protocols in order to handle display of content in a UITableView added either programmatically or via Storyboard/Nib.
Hopefully this will save someone some time. #Made2k's solution is fine, but does make your storyboard unnecessarily busy. If you don't need to use a UIViewController, then just do your work inside a regular UITableViewController and save yourself a headache.
If you want to use a UITableView in a UIViewController you have to make the ViewController a data source and a delegate of the TableView and then implement methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In case of a static table, in the cellForRowAtIndexPath you'd return outlets of the static cells. For a detailed description check out this answer:
https://stackoverflow.com/a/19110821/3110536
I ended up thinking about this in a different kind of way. The problem I thought I was having was I wanted all the features that a navigation controller provides, but I needed this to be the base of the controller, i.e. nothing to go back to. I was thinking that the only way to do this was to create a UIViewController and add the table view and such in there, but what I came up with is to simply just create a new navigation controller and now this view shows up as the root view like so:
I don't know if this is the best practice, but hopefully it can help somebody else if they are having this problem.
Man, following Hack really works!
You should give it a try!
In my requirement I wanted to add buttons in my Static cells too!and Toggle the visibility of the TableView
[self.tableView setHidden:YES/NO];
and Reload it with new data
[self.tableView reloadData];
and so many things is possible with that way of doing it!
https://stackoverflow.com/a/19110821/1752988
Hope the above link would help you! (Y)

How to separate ViewController methods between X files

I've started to develop for iPhone just 1 week ago, things are going very well, but I don't know even how to ask this question (english is not my natural language), let`s see if you will understand me.
I have a ViewController that do many things. Show some images, do some animations, scroll the images while change the white dot from Page Controller...well, this kind of stuff.
But my ViewController.m have SO MUCH code for just 1 file. Well, not YET.
What I want to do is to create another files in which I could write moar code, improving readability and organization. Like this:
ViewController.m (ViewController general code)
ViewController_Navigation.m
ViewController_ImagesScrolling.m
ViewController_DBActions.m
With their respective header files, if needed.
So, any ideas or examples of how can I do it?
The separation and encapsulation of function into separate classes is a common concept to break down masses of code. Methods that all have to do with one task can be lumped together as objects, usually UIView subclasses of some sort, or UIViewController subclasses for larger tasks that deserve their own screen of information. For example, you might have one that handles scrolling of images on its own once it's set up with the required UIImage's. Beyond that, however, you shouldn't generally split up a single controller's code. The controller contains all of the glue that holds the views it displays together along with the model in the MVC pattern. Thus, once all of the functionality that isn't reliant on the model has been sectioned off to views and you've partitioned the functionality into separate controllers in your interface, there is little you can do.
I would not recommend splitting the code into separate files because it all has one purpose: to coordinate what is going on on the screen and allow the views to interact with the model. However, what I usually do, is categorize and sort my code depending on what task it is managing. So, all of the life cycle and normal methods can go a the top, followed by all the table view methods, image viewer methods, etc.
This makes it easy to find code related to specific tasks, and even easier with the help of the pragma directive. Outside of any methods, in between your sorted groups of methods, you can use a pragma mark to assign an identifier to a location in your code, accessible through the jump bar, like I've done in the following example code.
#pragma mark - UIViewController Lifecycle Methods:
- (void) viewWillAppear{
//stuff
};
- (void) loadView{
//stuff
};
#pragma mark - UITableView Delegate & Datasource Methods:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//stuff
};
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//stuff
};
Now, if you were to go to the jump bar at the top of Xcode's code viewer and click on the right most object to find a method, you'd see this:
I don't believe that after sorting your code, marking it with pragma marks and separating all the code you can into other UIViews and UIViewControllers, you should feel the need to split your code into several files; you can just use the jump bar to go to any section of your code, effectively like swapping files would let you do. However, this way, you aren't fragmenting code from one class and leaving bits and pieces all over the place.
iOS is based on the MVC model. Hence you should be using the controllers for managing the model and views.
Ideally I would be doing this:
a. Implement separate controllers for managing
1. Images -> separate the views for displaying images
2. Database
3. whatever else you have...
b. Implement a separate controller for managing the above controllers.
You need to add more objects/ controllers class for the single view/xib.
And each one of them will be assigned/linked to your class.
-This is quite frequent design pattern in OSX, I hope this is even valid with ios.

How to add multiple instances of custom subviews in UIViewController

Often, when I'm making my apps, I'm in this situation : I have a UINavigationController, handling the view stack, some UIViewControllers, controlling their respective views...
But when I want to add several custom UIViews in my mainView, I don't know how to manage my code.
Each UIViewController needs to handle one and only one view (wich normally occupy all the screen size), and a view should not control their content (update it a the extrême limit).
You can't neither do this :
[myViewController1.view addSubview:childViewController.view];
So if I want to achieve something like this, what should I do ?
The orange parts have to be 3 instances of the same UIView(Controller?), but with a content depending of a NSObject (User, obviously).
I think this very important to segment your content, this should be an easy problem, but I found a lot of contradictory answers so, what's the best practice to handle this common issue?
Theses orange views should be instances of UIViewControllers in order for it to handle their UITableViewDatasource? Is addChildViewController relevant in this case?
I already found a lot of things which work, but I don't know what should I do...
Also, I'm using xibs.
Thanks in advance if you can help me (and other people I think).
You can do it either way (view or view controller) depending on how you want to handle things. Certainly, you can have one object be the data source for multiple tables, so in that case, you would just add multiple views. If, however, you want to keep your code more compartmentalized, then add view controllers, and have each control its own view -- to do this, you do need to use addChildViewController, and use the methods that Apple describes for creating custom container controllers. Alternatively, you can use container views in a storyboard which makes the process of creating custom container controllers simpler.
You're on the right path... Create separate instances of your subviews, and add them to your view. If you will have more than 3 (for instance, imagine coverview for your music, and you could scroll indefinitely left and right), I'd take a look at UICollectionViewController ... That will help manage cell re-use.
But, if it's just 3, just create three instances with different frames and add them to your view.
Here's how I'd do it:
each orange box will be a custom view (inherits from UIView)
the view will have the label, image and the tableview.
since you are not sure of the number of instances of these views you'd be using, its better to use some kind of tagging, so that you can have one place for the datasource and delegate methods of the tables in these orange views.
in the datasource and the delegate methods, you can make use of the tableView.tag (same as the orangeView.tag property).
I personally dislike having more than one viewController in a view (except the splitVC), probably because I haven't had a such requirement.
I dont see how a uiviewcontroller for orange box would help, over a uiview.
as #James Boutcher mentioned in his answer, UICollectionViews will simplify this issue further.
Why not creating a UIView class and overriding the drawRect method and then adding subView for this class in your myViewController1.view

ios/iphone sdk form management best practices

I'm working on an iPhone app that will have involve a lot of forms. Currently I have a ViewController class for each settings page which has an UITableView loaded with possible settings. When someone clicks on a setting they are taken taken to a new view to enter the form value, or allowed to enter things in place.
What's the best way to keep things DRY? What pieces of this implementation could be implemented once and re-used?
When someone clicks on a settings option which goes to a new view how can I create this view and add a text field according to the data type (uitextfield or picker or something else) in code?
You can programmatically:
create view hierarchy
UIButton
UILabel
You get the idea.
However, I would recommend getting your logic working for a few of the cases, and then it should become obvious what parts are redundant as you find yourself typing in the same thing over and over. At that point, refactor to get the redundant code into a re-usable form.
HTH.
If you have a tableView, the flow is to create the viewController of the selected settings in the didSelectCell method of your tableView delegate and to push it through the current viewController's navigation controller.
here's a sample:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.navigationController pushViewController:[self settingsViewControllerAtIndexPath:indexPath] animated:YES];
}
so you'll have to implement the method:
- (UIViewController*)settingsViewControllerAtIndexPath:(NSIndexPath *)indexPath;
wich will return the viewController managing the settings associated with the selected row of your root tableView.
If your forms are pretty statics, you should consider using a xib in order to minimize the amount of code needed. it isn't a perfect answer to your "how to keep DRY" but it's neat enough ;)
Good luck.

Resources