UITableViewController's table resize - objective-c

I have a UITableViewController and I need to resize the table vertically.
I can't use a UIViewController with a table inside.
There is a method?
Thanks!

This is only possible if your UITableViewController view is manually added to another superview. However, if you are planning to use the table view in a navigation controller or as a modal sheet you do not have control over the table view's size.
To have full control over the table view size:
Make you own subclass of UIViewController with UITableView outlet and a resource file.
Place a UITableView on top of its content view and resize it accordingly.
Make your view controller implement UITableViewDataSource and UITableViewDelegate protocols.
Connect outlets.

Instead of using a UITableViewController, it may be easier just to use a standard UIViewController, with a UITableView property.
E.g.:
#interface ContentsPopover : UIViewController <UITableViewDelegate, UITableViewDataSource>
//...
#property (nonatomic, strong) UITableView *theTableView;
//...
#end
That way, inside your UIViewController you can have the following code (possibly in viewDidLoad):
theTableView = [[UITableView alloc] initWithFrame:/*...*/ style:UITableViewStylePlain];
theTableView.delegate = self;
theTableView.dataSource = self;
theTableView.scrollEnabled = YES;
[self.view addSubview:theTableView];
// You can now change theTableView's frame property as needed
This is handy for when a UITableViewController wasn't quite what you're looking for.

Related

Custom view created with Interface Builder does not render when called in other views

I have an xib for the main window, and I created a custom view in the following steps:
Create a new class which inherits from NSView.
MyView.h:
#import <Cocoa/Cocoa.h>
IB_DESIGNABLE
#interface MyView : NSTableCellView
#end
MyView.m:
#import "MyView.h"
#implementation MyView
- (void)awakeFromNib {
NSLog(#"Post view awaking from nib.");
}
#end
Create a new xib, and set the root view's class to the class created above. And design in that xib.
Set outlets from the xib to the class.
And I tried to use this custom view in the main window in the following steps:
Drag a custom view to the main window's xib.
Set the class of that custom view to the class created above.
But nothing renders. From the log, I can see that code in awakeFromNib from the custom view class is executed. When I set the class to be IB_DESIGNABLE, the view gets empty in the main window's xib, different from what I designed.
I tried to set the file owner of the custom view's xib to the custom class, but nothing changed.
I guess the problem is that, the custom view's xib file is not actually loaded. When I googled it, there seem to be few references on this exact topic. So, how should I actually achieve this goal? I.e., design a view in IB, implement its methods in a class, associate these two, and expose it just like a system view for use in other xibs?
UPDATE:
I found a tutorial and realized what I lack (for correctly rendering the view when built). I have to add an outlet from the view in the xib to the view class:
#property (nonatomic, strong) IBOutlet NSView *view;
, and then load it in the (id)initWithCoder:(NSCoder *)coder method.
[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self topLevelObjects:nil];
[self addSubview:self.view];
But the view still won't render in the interface builder.
Your guess is correct: the xib is not being loaded. The nib loader doesn't know about your custom view's nib. The nib framework doesn't provide a facility for defining that connection, so you need to write code to load the xib.
Here's what I'd do. Add a contentView property to your custom view:
#interface MyView ()
#property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;
#end
In your custom view's nib, set the custom class of the root view back to NSView and disconnect all the (no-longer-valid) outlet connections from it. Set the custom class of File's Owner to your custom class name (e.g. MyView). Connect the root view to File's Owner's contentView outlet, and connect all the other outlets from File's Owner to the appropriate objects in the nib.
Then implement awakeFromNib in your custom view subclass to load the nib and add the content view as a subview:
#implementation MyView {
BOOL hasLoadedOwnNib: 1;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self loadOwnNibIfNeeded];
}
- (void)loadOwnNibIfNeeded {
if (hasLoadedOwnNib) {
return;
}
hasLoadedOwnNib = YES;
[[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass(self.class) owner:self topLevelObjects:nil];
self.contentView.frame = self.bounds;
self.contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[self addSubview:self.contentView];
}
#end
Note that you have to be careful not to allow infinite recursion. When your app loads the main window's nib, it will create an instance of MyView and (eventually) send it awakeFromNib. Then, in awakeFromNib, MyView loads its own nib, where it is the File's Owner. The nib loader sends awakeFromNib to File's Owner, and this will happen while you're already in -[MyView awakeFromNib]. If you don't check for this, you get a stack overflow due to unbounded recursion.
You aren't providing any code, but here are some sanity checks:
Are you specifying the nib name correctly? In iOS its caps sensitive, but I don't think it is for you.
Check the package, is the nib actually there? Make sure it is part of the target you are building.
Could also be a frame issue. Make sure your auto-resizing parameters are set up correctly and that everything is in frame.
Another check you can do is set your IBOutlets to the actual frame of a UIView (or other) that you are interested in. Then in awakeFromNib, you can make sure their frame exists, or that they exist at all.

How can i make a UITabbar like this?

I would like to create a UITabbar like below but i don't know what is the logic to do that.
Here is the large answer:
First of all, you will need to create a UIView subclass to get a view that looks like the bar that you want. It can be composed by a background UIImageView and three buttons.
Then, the best thing would be to create a subclass of the UITabBarController and in its viewDidLoad or at any point where the flow will go through just once, you instantiate one view of type specified at first point. You should place the frame of this view in order to hide the original tabbar of the controller.
This would be the custom bar header file:
#interface CustomBar : UIView
{
}
#property (nonatomic, retain) UIImageView *backgroundView;
#property (nonatomic, retain) NSArray *buttons;
#end
You can easily complete the implementation. You can try to look for how to instantiate it with a nib file to make it easier to design it. In order to test, you can first just set the background color to green or something visible.
Then, this would be the subclass of the UITabBarController class:
#interface CustomTabBarController : UITabBarController
#property (nonatomic, retain) CustomBar *customBar;
#end
#implementation CustomTabBarController
- (void)viewDidLoad
{
[super viewDidLoad];
self.customBar = [[[CustomBar alloc] initWithFrame:[self.tabBar frame]] autorelease];
[self.view addSubview:self.customBar];
}
#end
Please, remember to implement the dealloc if you are not using ARC.
The thing I am not sorting out here is how to create the communication between the buttons from the custombar and the tabbarcontroller. This should be solved by delegates. If you need help with that, I will complete that too.
Good luck!

Access a UITextField in another UIViewControllers view

This is how I use a XIB view controllers view as a subview in the MainViewController:
UIViewController *nameController = [[NameSubViewController alloc] initWithNibName:#"NameSubViewController" bundle:nil];
nameSubView = [nameController view];
[self.view addSubview:nameSubView];
The nameController view contains a UITextField property. Can I somehow access this property from MainViewController?
EDIT:
If I create a property for the textField in the View Controller too, I'm still not able to get it in MainViewController. Think it's because of the UIView subclassed causing problems?
NameSubViewController.h:
#import <UIKit/UIKit.h>
#interface NameSubViewController : UIViewController
#property (nonatomic, strong) IBOutlet UITextField *textField;
#end
NameSubView.h:
#import <UIKit/UIKit.h>
#interface NameSubView : UIView
#property (nonatomic, strong) IBOutlet UITextField *textField;
- (IBAction)textFieldReturn:(id)sender;
#end
Connections in IB for NameSubViewController:
Connections, NameSubViewController
Connections in IB for NameSubView:
Connections, NameSubView
Did you create an outlet for the textfield in your nameController? Do that, and then you can retrieve the value using
nameController.textField.text
In the nib file, click on the file's owner icon (on the left of the nib), and set it's class to your UIView's subclass using the inspector on the right.
Why are you adding view from Controller A in Controller B. Isn't it better that you create a view by only using its xib file and add that view to your controllers view.
For accessing field, you can assign a tag to your textfield, and where ever in your code you need it, call
self.view viewWithTag:<#(NSInteger)#> method.

Proper way to inherit UITableViewController?

My problem is I can't show inherited class from UITableViewController with static cells. I am using storyboard for easy custom cells setup (I want to get a Settings App like behavior) in UITableViewController. But I need to nest it in another UIViewController which shows custom top bar (like navigation bar panel). So when I load my UITableViewController with this structure:
#import <UIKit/UIKit.h>
#interface MyCoolTableVC : UITableViewController
#end
I get no issues, all custom cells which I set in storyboard builder are shown in proper way in grouped table view. But when I am using subclass from UITableViewController:
#import <UIKit/UIKit.h>
#import "MyCoolTableVCSubclass.h"
#interface MyCoolTableVC : MyCoolTableVCSubclass
#end
I get this result:
which shows wild appearance of tableView, without sections and custom cells.
I load my controller with this code, if it helps:
UIViewController *vcToGo = nil;
UIStoryboard *storyBoard = [[UIStoryboard storyboardWithName:#"MyCoolStoryboard" bundle:nil] init];
vcToGo = [storyBoard instantiateViewControllerWithIdentifier:#"profileTable"];
[self.navigationController pushViewController:vcToGo animated:YES];
To use static cells, the datasource of the table view has to be set to a UITableViewController subclass, and you must not implement the datasource methods yourself.
The base UITableViewController provides everything to the table view in its own implementation of cellForRowAtIndexPath etc, using what you have put in the storyboard. So if your datasource does not inherit from UITableViewController, it will not be able to populate the table.
(note - This is what I assume is happening based on my own experiments, the internals of UITableViewController are not available to me)

Loading custom UIView in UIViewController's main view

I have subclassed UIView and created a NIB that controls the main logic for my application.
Hoping the view will scale nicely, I want to use it for both the iPhone and iPad versions of the app.
On the iPhone the view will cover the full screen. On the iPad the view will cover only part of the screen.
I have read that you shouldn't use UIViewControllers to control only part of the screen. So, I am trying to embed the custom UIView in the main UIViewController's view using IB.
How can this be done?
After a lot of trial and error I found a solution based on an approach explained in the following question, answered by Brian Webster.
The solution was originally suggested for a Cocoa environment. I hope it is valid in an iOS environment as well.
Create the main view controller with a NIB-file. In the NIB, the File's Owner should correspond to the class of your main view controller.
Create a custom view controller with a NIB-file. In this NIB, the File's Owner should correspond to the class of your custom view controller.
Create a custom view controller property in your main view controller class.
Create an UIView property in the main view controller class. It will hold your custom view controller's view. Define it as an IBOutlet, so it can be linked in the NIB.
Drop a UIView in your main view controller's NIB. Link it to the main view controller's view IBOutlet. It will be used as a placeholder for the custom view.
In the main view controller's viewDidLoad method, load the custom view controllers NIB, determine the custom view's frame size and copy the view in the main view controller's view.
Here is some code:
MainViewController.h
#interface MainViewController : UIViewController {
CustomViewController *customViewController;
UIView *customView;
}
#property (nonatomic, retain) CustomViewController *customViewController;
#property (nonatomic, retain) IBOutlet UIView *customView;
#end
MainViewController.m
- (void)viewDidLoad {
CustomViewController *controller = [[CustomViewController alloc] initWithNibName:#"CustomViewController" bundle:nil];
self.customViewController = controller;
[controller release];
customViewController.view.frame = customView.frame;
customViewController.view.autoresizingMask = customView.autoresizingMask;
[customView removeFromSuperview];
[self.view addSubview:customViewController.view];
self.customView = customViewController.view;
[super viewDidLoad];
}
Add an IBOutlet propertyfor your custom UIView to the UIViewController, and additional outlets for any subviews you wish to access.
Go to Interface Builder, select the "File's Owner" object in your NIB and in the Inspector go the rightmost tab set its class to match your UIViewController's class.
Connect the IBOutlet from step one on the "File's Owner" to your custom UIView.
In XCode, when you need to load your view, do something like this:
--
[[NSBundle mainBundle] loadNibNamed:#"MyNib" owner:self options:0];
self.myCustomView.frame=self.view.bounds; // make view fill screen - customize as necessary
[self.view addSubview:self.myCustomView];
When you load the NIB, the outlet(s) you set up in step 1 will be populated with the objects loaded from your NIB.