Static UITableView not fullscreen - objective-c

For my registration form, I am currently using a UITableView which isn't fullscreen and I add cells programmatically through hardcoding the datasource methods. By the time the whole class got very complex and huge.
Pastebin link
The cells are custom and have a UILabel and a UITextfield. Now one of the cells should have a button instead of the textfield. This would make the whole thing more complex then it should be, in my opinion. So my thought was using the static feature of the tableview in the storyboard. But this requiers a UITableViewController, if I use one the TableView is always fullscreen. Is there a way to se the static feature without a fullscreen TableView??

If you have a fixed number of cells, the static table view controller is a good option. Instead of implementing the datasource methods, as you mentioned, you can include each input field as an IB outlet.
If you want a static table view controller that is not full-width, embed the table view controller inside a container view.
For example, create a new view controller, add a container view object w/ the desired width in this new view controller, and then connect your static table view controller to the container view.
Note that the static table view controller becomes a childViewController of the enclosing view controller. You can facilitate access to the textFields from the enclosing view controller w/ a weak property to the textFields w/in the child view controller.
- (UITextField *)surnameTextField
{
UITextField *textField;
// reference childController that is initiated via containerView
if ([[self.childViewControllers lastObject] isKindOfClass:[NameViewController class]])
{
NameViewController *nameVC = [self.childViewControllers lastObject];
textField = nameVC.surnameTextField;
}
return textField;
}

You do not need to use a UITableViewController. Just drag and drop a table view from the control palette onto a UIViewController in your storyboard. Size and position it how you want to and add any other controls to the UIViewController that you need.
In the property sheet for the UITableView set the content type to 'Static Cells' then define your cells how you want them.

Related

How to set UITableViewController custom class programmatically?

This is my storyboard:
The UITableViewController, has a generic UITableCell (MMSwitchTableCell) that has an image, a label and switch.
The idea is to be able to create different UITableViewControllers that present different data with the same layout i.e with the same cell object and same behavior. for example one time the UITableView has a list of cells that helps you select fruits, second UITable helps you select furniture.
The two UITablesViewController have no relation between them (no inheritance or aggregation), they are different instances in different viewControllers, I only want to re-use the designed control and the UITableCell code.
So my code has a UIViewController where I declare a property:
#property (strong, nonatomic) MMGoSeePopoverTableViewController* goSeePopoverTableViewController;
and lazy load it:
-(MMGoSeePopoverTableViewController*) goSeePopoverTableViewController
{
if(_goSeePopoverTableViewController == nil)
{
_goSeePopoverTableViewController =(MMGoSeePopoverTableViewController*)
[self.storyboard instantiateViewControllerWithIdentifier:#"switchPopover"];
}
return _goSeePopoverTableViewController;
}
and a second UIViewController in which I declare a property:
#property (strong, nonatomic) MMLayersPopoverTableViewController* layersPopoverTableViewController;
and lazy load it:
-(MMLayersPopoverTableViewController*) layersPopoverTableViewController
{
if(_layersPopoverTableViewController == nil)
{
_layersPopoverTableViewController =(MMLayersPopoverTableViewController*)
[self.storyboard instantiateViewControllerWithIdentifier:#"switchPopover"];
}
return _layersPopoverTableViewController;
}
In the storyboard I've set the custom class to MMLayersPopoverTableViewController, instead I wish to leave it blank and somehow set it in the code. I guess I should do this inside the lazy loaders, but I can't figure how.
Edit
The suggested "This question may already have an answer here:" is not the same as what I'm asking. I have amended the post to explain my problem better.
The idea is to be able to create different UITableViewControllers that
present different data with the same layout i.e with the same cell
object & same behavior.
This sounds like a case where you should use a .xib file instead of a storyboard. The advantage of storyboards compared to .xib files is that you can see the structure of the app in terms of views and the corresponding view controllers. In your case, though, you're trying to reuse the same view with different view controllers. Putting your table in a .xib file that's owned by the view controller will let you load the same table, cell, etc. with whatever view controller you decide to instantiate.
In your .xib file, set the type of the File's Owner proxy to some common superclass of all your view controller classes which contains all the necessary functionality. For example, if all your view controllers are derived from UITableViewController and you don't need any special outlets, set the type to UITableViewController and connect the table to the proxy's tableView outlet. If your view controllers have other common behavior, put all that in a subclass of UITableViewController, use that as the proxy's type, and derive the other view controllers from that class.
Once you've done all that, you can use the -initWithNibName:bundle: method to initialize any of your view controllers and load the same view:
// in one place...
MMGoSeePopoverTableViewController *goSeeVC = [[MMGoSeePopoverTableViewController alloc]
initWithNibName:#"CommonTableView.xib" bundle:nil"];
// and in some other place...
MMLayersPopoverTableViewController *layersVC = [[MMLayersPopoverTableViewController alloc]
initWithNibName:#"CommonTableView.xib" bundle:nil"];

Link XIB to a custom NSView in a Framework

I am writing a Cocoa Framework (not an Application), it contains the definition of a customized NSView; the framework will be loaded in other applications, and the customized NSView will be dragged to the GUI of the applications and become initialized
The question is that I want to include a XIB file in the Framework
I want to add a button and a label to the XIB (in the framework), but the view in the application that consumes the framework, won't show the button and the label
I already set the File's Owner of XIB to the custom NSView in the framework
What else should I do?
Have the view load the nib and move the button, label, etc., from the view in the nib to itself.
It'll be easiest to do this just by getting the subviews of the nib's view and doing this for all of them.
If your nib uses Auto Layout, I think you'll also need to bring across any constraints owned by the nib's view, and you may also need to edit or replace any constraints that refer to that view (e.g., if a view is set to be X points away from an edge of the nib's view).
You may also need to do extra work to change the new view's frame, or to change the frames of the subviews (whether by relocation, resizing, or both) to match the frame given for the new view.
Yeah, I just solved the issue, and I hope the details are helpful to others.
In the framework, there is a complicated subclass of NSView, which contains many controls such as NSSplitView NSOutlineView and IKImageBrowserView, NSPathControl and etc; the framework contains a H file, a M file and a XIB file; H and M define the MyView class; in the XIB, there is a View object whose class is MyView.
On the application side, users need to drag a NSView item onto the main window of their app, and assign an outlet to the view, let's say mainView, and in the applicationDidFinishLaunching function of the "consumer" app, the follow code is necessary
NSBundle *frameworkBundle = [NSBundle bundleForClass:[MyView class]];
NSNib *nibby = [[[NSNib alloc] initWithNibNamed:#"MyView" bundle:frameworkBundle] autorelease];
NSArray *topLevelObjects = nil;
BOOL flag = [nibby instantiateNibWithOwner:nil topLevelObjects:&topLevelObjects];
assert(flag);
for (id topLevelObject in topLevelObjects) {
if ([topLevelObject isKindOfClass:[MyView class]]) {
[mainView addSubview: topLevelObject];
MyView* xView = topLevelObject;
[xView setFrameSize:mainView.frame.size];
break;
}
}
In the code above, the XIB files is loaded, thus the MyView object is initialized, then we fetch it out of the XIB, resize it and add it to the main view of the window

Change self.view's class type

I have a app out for testing right now that's almost completely done - just a few bug fixes left. Unfortunately, the customer decided that they'd like the entire main page of the app to be inside of a scroll view (so that there's more room for the table at the bottom). I already have everything set up and I don't really want to move everything and change references. Is there an easy way to change the class of the main view to a scroll view? I've already tried changing the class in IB and setting the class type in the init method. If there isn't I'll probably just throw the top section of the view into a nib file and load it as a custom cell.
-EDIT- I ended up changing the class type in IB and then doing
[(UIScrollView *) self.view setScrollEnabled:YES];
[(UIScrollView *) self.view setContentSize:CGSizeMake(0,2000)];
in viewDidLoad. Thanks for the help, wish I could accept all your answers.
When you are referring to [self view], I am going to assume you mean in a view controller. The view of a view controller can be any view that derives from UIView. Thus a scrollview is completely acceptable.
I don't really want to move everything and change references.
what would you have to move? why would you have to change references? Only thing you should need to do is add a scroll view to your view controller, set the view controllers view to it, and add the current view as a subview to the new scroll view. No references need to be changed, nothing has to be moved.
Refer to loadView method in documentation of view controller.
Here is a simple (untested!) example
- (void)loadView {
UIScrollView *scrollView = [[UIScrollView alloc] init] autorelease];
//Set the properties of scrollview appropriately....
self.view = scrollView;
}
Now the root view of your view controller will be a scroll view.
Note
- As the documentation states, do not do this if you are using interface builder to initialize your views/view controller. I could not tell from your description if this was the case or not. If it is, you should be able to change the view type in interface builder.
You need to set the contentSize property of your scrollview.
Since you are using IB, the easiest way to do this is to put all your UI elements into a view and add this single view to your scroll view. In the viewDidLoad method, set the content size of the scrollview to be the same size as the view that contains all your UI.
As an aside, there are much easier ways to reference views than walking down the view hierarchy, as you seem to be doing. viewcontroller.view.something.tableview. Add a connection to the tableview from your view controller in IB and it doesn't matter where that tableview is in the view hierarchy. You'll always be able to reach it from viewcontroller.tableview, no matter how you rearrange your nibs.
I think you have to use a pointer with proper type. Example for Google Maps: let's say you changed you base view's class to GMSMapView.
MapViewController.h
#property GMSMapView *mapView;
MapViewController.m
-(void)awakeFromNib{
[super awakeFromNib];
self.mapView = (GMSMapView*)self.view;
// ... etc.
}

Object mixup between programmatically created view and interface builder placeholder

I have a view controller which contains a scroll view. Inside the scroll view there is another UI core graphics view. In the view controller I create a temp object for the core graphics view and assign some data to it, then assign it to the attribute of the view controller. Eg: In the view controller:
#interface controller : UIViewController {
GraphView *graph;
}
#property ... IBOutlet GraphView *graph;
#implementation
GraphView *temp = [[GraphView alloc] init];
temp.someArray = anExistingDataArray;
self.graph = temp;
In IB, I open the view controller nib and add a scroll view, and embed a view and assign it the core graphics view class. Then hook up the IBOutlet from that view to the attribute in the view controller.
My problem is that the view controller creates the temp view object, assigns it to itself, with the correct data, however IB seems to instantiate its own object (different memory ID) and displays that, instead of the one in the view controller.
What is the correct way to build this type of setup?
If you drag an object into a nib, IB creates and archives that object. This is why you don't have to alloc/init views that you create in IB.
I'm guessing that you are creating your view in IB so that you can get the geometry correct, or...? It's rather unusual to create a view and then immediately replace it at run-time. More common, for geometric purposes, is to create a container view in IB and then add your programmatically-created views as subviews of that.
Your code left out the most important piece of this, though, which is when it's getting run. Is it in -init...? -awakeFromNib? -loadView? -viewDidLoad? The exact location matters since these occur in a well-defined sequence. If you put your code in the wrong place, it will run before the nib is unarchived and fully reconnected, so the nib will clobber whatever your code did.
So: when is your [self setGraph] (I can't bring myself to use dot syntax) code getting run?

How to control a view with different UITableViewControllers based on parent table selection

I have a Split-View iPad application and I fixed the selections in the popover (RootViewController) to be static, let's say red, yellow, and blue. When my app starts I have preselected red or the top static text in the cell. I was able to add UITableViewDelegate and UITableViewDataSource with the other templates in DetailViewController. It's the one with the popover-no-popover default split-view app.
I added the row count and the cell method and voila' my test array populated the detail table. I want a separate controller (delegate and source) for each selection the user chooses to be driven from didSelectRowAtIndexPath in the RootViewController.
Should I just add the delegate and datasource templates to the DetailViewController and switch the data based on selections in the RootViewController view?
Or, would my multiple controller pattern be better design?
I would like some assistance as to how to get the outside controller to have control of the DetailViewController's UITableView. The DetailViewController is where I instantiate the add button and such to the toolbar. E.g. when I added the single (Red) test controller to the DetailViewController, any connection to the TableView wasn't seemingly automatic in IB. You could hover and then it would eventually connect to "View" (ultimately the UITableView). I've tried everything and I cannot get a simple delegate and datasource controller with a simple NSArray to populate the DetailViewController's table view from RootViewController's didSelectRowAtIndexPath. This method works because I've debugged and NSLogged the selections. I'm not creating my ProjectViewController (test or first static text in RootViewController) correctly. I'll paste some code that I've tried here too.
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// select static row and view controller
Punch *obj = [self.punchList punchAtIndex:indexPath.row];
NSLog(#"Selected punch object: %#", obj.name);
ProjectViewController *projectViewController = [[UITableViewController alloc] init];
[projectViewController tableView:detailViewController.tmpView];
}
The ProjectViewController code works if hard-coded in DetailViewController, i.e. the required methods, the count, and the array loaded cells and the I want this data population in separate controllers because I'm going to use Core-Data in the end.