I've been struggling to add a UIView above my UITableViewController. Through searches, reading and experimenting I've determined that instead of a UITableViewController I should just be using a UIViewController. I'm having a hard time making this work for a variety of reasons and I'd like to just start fresh with a better architecture.
Basically I'm looking for sample code / tutorials that could help me create the following completely programmatically (no NIBS):
- Navigation-based Layout
- UIViewController
-- UIView
--- UITableView
--- Etc.
The reason why I want a UIView above my UITableView is I want to be able to add UIViews above my table.
-UPDATE-
Adding code to make this more clear:
JMoviesListViewController.m - UITableViewController subclass
- (void)loadView
{
NSLog(#"loadView called");
UIView *baseView = [[[UIView alloc] init] autorelease];
TISwipeableTableView * aTableView = [[[TISwipeableTableView alloc] init] autorelease];
[aTableView setDelegate:self];
[aTableView setDataSource:self];
[aTableView setSwipeDelegate:self];
[aTableView setRowHeight:54];
[baseView addSubview:aTableView];
self.view = baseView;
[super loadView];
}
- (void)viewDidLoad {
listOfMovies = [[NSMutableArray alloc] init];
UIView *myProgView = (UIView *)self.progView; // progView is a method that returns a UIView
[self.view insertSubview:myProgView aboveSubview:self.tableView];
[self.navigationItem setTitle:#"Now Playing"];
movies = [[Movies alloc] init];
movies.delegate = self;
[movies getMovies:[NSURL URLWithString:apiQuery]];
[super viewDidLoad];
}
- (UIView *)progView {
if (progView == nil)
{
// create a progress view
//x,y,w,h
progView = [[UIView alloc] initWithFrame:CGRectMake(110, 110, 95, 30)];
progView.backgroundColor = [UIColor grayColor];
progView.tag = 1; // tag this view for later so we can remove it from recycled table cells
progView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
progView.layer.cornerRadius = 5;
UILabel *activityLabel = [[UILabel alloc] init];
activityLabel.text = NSLocalizedString(#"Loading...", #"string1");
activityLabel.backgroundColor = [UIColor grayColor];
activityLabel.textColor = [UIColor whiteColor];
activityLabel.font = [UIFont systemFontOfSize:14];
[progView addSubview:activityLabel];
activityLabel.frame = CGRectMake(5, 2, 70, 25);
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[activityIndicator startAnimating];
[progView addSubview:activityIndicator];
activityIndicator.frame = CGRectMake(70, 5, 20, 20);
}
return progView;
}
To be clear, the code works fine, the problem is that the cell lines of the table are "bleeding through" the UIView spinner that is inserted with this line:
[self.view insertSubview:myProgView aboveSubview:self.tableView];
leading me to believe that myProgView is not aboveSubview:self.tableView.
Views and controllers are separate things. You can have a hierarchy of view controllers and a hierarchy of views. But they're not interleaved, as the title of posts suggests (I know, Interface Builder displays them as a single hierarchy, but views and controllers are more like two parallel hierarchies).
Anyway, you can easily have a view controller set up whatever views you want in code. Override the loadView method, create a view that you assign to self.view, then add subviews to that view.
For example:
- (void)loadView
{
UIView *view = [[[UIView alloc] init] autorelease];
UITableView *tableView = [[[UITableView alloc] init] autorelease];
tableView.dataSource = self;
tableView.delegate = self;
[view addSubview:tableView];
self.view = view;
}
Your view controller should either inherit UITableViewController or implement the UITableViewDataSource and UITableViewDelegate protocols.
You have to actually specify the layout of your different views, not just add them as subviews. Try reading a tutorial about using AutoLayout programmatically.
You also want to set up all your views in loadView. There you can set the bottom of your extra view to the top of your table view.
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view = [[[UIView alloc] initwithFrame:CGRectMake(set your frame)] autorelease];
UITableView *tableView = [[[UITableView alloc] initwithFrame:CGRectMake(set your frame)] autorelease];
tableView.dataSource = self;
tableView.delegate = self;
[view addSubview:tableView];
}
if you are using **ARC** remove autorelease.
Related
I am trying to resize a simple UITableView that fits between a navigationbar and a tabbar.
- (void)loadView
{
[super loadView];
UITableView *tableview = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f) style:UITableViewStylePlain];
tableview.dataSource = self;
tableview.delegate = self;
self.tableView = tableview;
[tableview release];
[self.view addSubview:self.tableView];
}
I have removed the autoresizing I have been trying to do because it does not work, any help is MUCH appreciated!
1) Create your view programmatically in loadView, do not call [super loadView]
2) create tableView with size same as application screen, use [[UIScreen mainScreen] applicationFrame] or something similar
3) set UIViewAutoresizingFlexibleHeight for tableView
..Edited answer to be more clear..
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
tableView.frame = self.view.bounds;
[self.view addSubview:tableView];
When I remove the [super loadView]; the view wont display. The superclass is UIViewController.
- (void)loadView
{
[super loadView];
UITableView *tableview = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f) style:UITableViewStylePlain];
tableview.dataSource = self;
tableview.delegate = self;
self.tableView = tableview;
[tableview release];
[self.view addSubview:self.tableView];
}
Any idea why? Thanks in advance!
1) UIViewController Class Reference, loadView section
Your custom implementation of this method should not call super.
2) You have to set view property to something. After all this method is called loadView :). Instead of [self.view addSubview:self.tableView]; try
self.view = tableView;
If you look at the view programming guide, it mentions that if you override [loadView], you should construct your own view.
default loadView will look at bunch of stuff, like load from nib first, then construct normal view.
So, just construct a view, and assign it to self.view -
UIView *view = [[UIView alloc] initWithFrame ...];
self.view = view;
[view release];
then it should be fine.
edit: example with your code:
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f)];
self.view = view;
[view release];
UITableView *tableview = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f) style:UITableViewStylePlain];
tableview.dataSource = self;
tableview.delegate = self;
self.tableView = tableview;
[tableview release];
[self.view addSubview:self.tableView];
}
edit2: link to viewcontroller programming guide:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/BasicViewControllers/BasicViewControllers.html#//apple_ref/doc/uid/TP40007457-CH101-SW1
Look at custom view controller section, Creating the View Programmatically, and few other places in that doc.
I think you wanna move that [ tableview release ] after the addSubview.
This is because you never assign the view property in the code. When in the last line you access the view property, it causes -loadView to be called again, which results in a endless loop.
This is what I tried. Nothing appears on the screen and none of the UITableView methods that you are supposed to implement are getting called.
-(void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = view;
[view release];
}
- (void)viewDidLoad
{
[super viewDidLoad];
UITableViewController *TVC = [[[UITableViewController alloc]
initWithStyle:UITableViewStylePlain] autorelease];
CGRect cgRct = CGRectMake(0, 10, 320, 100);
UIView *newView = [[UIView alloc] initWithFrame:cgRct];
TVC.view = newView;
[newView release];
[self.view addSubview:TVC.view];
}
I've looked for good examples and tutorials on doing this programmatically but there are none.
What I am trying to achieve is a Table that doenst take up my who screen. Maybe 3/4 of my screen would be good.
Many Thanks
Code
The problem is that you're creating a UITableViewController, which is a UIViewController, and will expect to be on the nav stack. What you want to do is create a UITableView, which is a UIView. You are also not setting the table's delegate and data source, which you will need to do to get calbacks.
Your viewDidLoad should look something like this
- (void)viewDidLoad
{
[super viewDidLoad];
UITableView *table = [[[UITableView alloc] initWithStyle:UITableViewStylePlain] autorelease];
table.dataSource = self;
table.delegate = self;
table.frame = CGRectMake(0, 10, 320, 100);
[self.view addSubview:table];
}
(Note that if you're going to need access to the table outside of the callbacks, you should save it in an ivar rather than declaring it locally, and should retain it. Let me know if you need a few more lines of code to show you what I mean)
Make sure you set the delegate of TVC, with
TVC.delegate = self;
That's the reason why none of those methods are getting called. Also, make sure your class implements the UITableViewDelegate protocol by changing your interface declaration to
#interface YourViewController : UIViewController <UITableViewDelegate> {
//declare variables here
}
Also, equally important, don't set TVC.view, as this already happens when you initialize the view controller. You're just setting it to a blank view, which is why you're not seeing anything.
iOS7 seems to like this way of init'ing the tableview:
//make tableview
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 81, 200, 200) style:UITableViewStylePlain];
table.dataSource = self;
table.delegate = self;
[self.dataView addSubview:table];
try that out. Hope it helps someone.
UIView *newView = [[UIView alloc] initWithFrame:cgRct];
TVC.view = newView;
I'll give you a hint. Here you are setting the view of the UITableViewController to an EMPTY VIEW...
I'm having a bit of difficulty trying to build my view. Everything works out great up to the point where I need to insert a UIToolBar into my view. The tableView is placed where I expected it to be placed. The UIToolBar on the other hand, scrolls up and down with the table, it doesn't remain fixed as it should. It also looks rather odd when put on the screen -- I'm guessing because the calculation to place it isn't right? Attached to this question is a screenshot as well as the code I've used to build this. Thanks for your help in spotting out what I'm doing incorrect. Screenshot: http://dl-web.dropbox.com/u/57676/screenshots/broketoolbar.png
The code:
- (void)loadView
{
[super loadView];
// TableViews that wish to utilize tableView footers/headers should override this method.
UITableView *aTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
aTableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight);
aTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
aTableView.delegate = self;
aTableView.dataSource = dataSource;
self.tableView = aTableView;
self.view = tableView;
[aTableView release];
UIToolbar *toolbar = [UIToolbar new];
[toolbar setBarStyle:UIBarStyleBlackOpaque];
[toolbar sizeToFit];
CGFloat toolbarHeight = [toolbar frame].size.height;
CGRect mainViewBounds = self.view.bounds;
[toolbar setFrame:CGRectMake(CGRectGetMinX(mainViewBounds),
CGRectGetMinY(mainViewBounds) + CGRectGetHeight(mainViewBounds) - (toolbarHeight * 2.0),
CGRectGetWidth(mainViewBounds),
toolbarHeight)];
[self.view insertSubview:toolbar aboveSubview:self.tableView];
[toolbar release];
}
because self.view is tableView onto which you added toolbar.
I have been all over the place, seems the UITableView with a static background issue is well documented, but no one with a straight forward solution?
Im building my TableViews entirely in code, like this:
UIViewController *tableViewController = [[TableViewController alloc] init];
navigationController = [[UINavigationController alloc]
initWithRootViewController:tableViewController];
[tableViewController release];
[window addSubview:navigationController.view];
The window is my main UIWindow build for me in the app delegate. From here on I need to build a few different TableViews (controlled by the navigationController), some with fetchedResultsControllers, custom cells and so on. I prefer to do this completely in code, not using nib's as this would result in either having customization spread between code and IB or having to build and maintain 6+ different Nibs.
I simply can't find a working example where a tableViewController Class sets it's own background image. If I do this inside one of my TableViews (extending UITableViewController):
self.tableView.backgroundColor = backgroundColor;
I, of course, get the tableView's background colored (which incidentally colors the cell's as well, think the cell's inherits their color from the tableView?) but I wish to have a static background image that my cells slide up and down on top of. Not a "background image" that slides up and down with the users gestures.
Exactly what the GroupedStyle tableView offers, but in a PlainStyle tableView:) .. and done using code, not IB.
I guess I have to clear the background color of the table view, then set the Cells color when configuring them so they don't turn out transparent. And then somehow "sneak" a background image below the tableView view from inside the tableView instance?
How will I go about this, the best solution would to be able to do this in viewDidLoad or any other function inside my TableViewController, to keep all my customization in one place.
Hope someone can help me, Im all 'googled out' :) Thanks!
You need to set up your controller as a UIViewController, not a UITableViewController. Then add the tableview programmatically above a background imageView.
#interface SomeController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
...
UITableView *tableView;
...
}
#property (nonatomic, retain) UITableView *tableView;
#end
#implementation SomeController
#synthesize tableView;
...
- (void)loadView {
[super loadView];
UIImageView *v = [[[UIImageView alloc] initWithFrame:self.view.bounds] autorelease];
[v setImage:[UIImage imageNamed:#"table_background.png"]];
[self.view addSubview:v];
self.tableView = [[[UITableView alloc] initWithFrame:self.view.bounds] autorelease];
[self.tableView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:self.tableView];
}
...
#end
All of this jumping through hoops is unnecessary if you're targeting > iOS 3.2, where you can use the new backgroundView property to set a UIImageView directly, e.g.:
// In your UITableViewController subclass
- (void)viewDidLoad
{
[super viewDidLoad];
UIImageView *view = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"]];
self.tableView.backgroundView = view;
}
Ok, now it is running:)
My tableView was not populated with my cells, so breakPointing through the thing I found out
that even though I had implemented the TableViewDataSource and TableViewDelegate, this was only in the main view, I needed to set the delegate and datasource of the tableview to = self.
For others seeking an answer to this here is the method as it ended up with Coneybeares help:
- (void)loadView {
[super loadView];
UIImageView *imageView = [[[UIImageView alloc] initWithFrame:self.view.bounds] autorelease];
[imageView setImage:[UIImage imageNamed:#"carbon_background.png"]];
[self.view addSubview:imageView];
[self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds] autorelease];
[self.tableView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:self.tableView];
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
Thanks Coneybeare.
It doesn't crash anymore and the background image turns up just perfect (along with my navigationController in the top)
However, still no visible tableView? just the background image and the navigationControllerBar:
This is my implementation:
- (void)loadView {
[super loadView];
UIImageView *imageView = [[[UIImageView alloc] initWithFrame:self.view.bounds] autorelease];
[imageView setImage:[UIImage imageNamed:#"carbon_background.png"]];
[self.view addSubview:imageView];
[self.tableView = [[UIView alloc] initWithFrame:self.view.bounds] autorelease];
[self.tableView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:self.tableView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"Hello, World";
return cell;
}
//commit edit, didSelectRow, memory … etc.
The forum wasn't up for an entire .m file in one go.
Please tell me if I left something out that could help indicate an error.
I thought maybe it was the order of the layers and tried this without any luck:
[self.view sendSubviewToBack:imageView];
Hope I missed something obvious.
Thanks for your time:)
Some tips:
If using a UISplitViewController:
splitViewController.view.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
If using a UINavigationController:
navigationController.view.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
If using both a UISplitViewController and a UINavigationController:
navigationController.view.backgroundColor = [UIColor clearColor];
splitViewController.view.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
Be sure to set the background color of any UIView you want to see through that is on top of the UINavigationController or UISplitViewController to [UIColor clearColor].