UITableView appearance with ios5 UIAppearance not working correctly? - ios5

I'm trying to set the background for a number of UITableViews that are loaded inside a UINavigationController. I'm using the appearance proxy added in iOS 5 but it's not working how I'm expecting it to.
The app uses a UISplitViewController, with the master view being the UINavigationController.
Inside this, I have a UITableViewController subclass called PBMasterTableViewController.
In my AppDelegate I have the following :
UIImageView *bgView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"menuBg.png"]] autorelease];
[[UITableView appearanceWhenContainedIn:[PBMasterTableViewController_Ipad class], nil] setBackgroundView:bgView];
This is working fine, and my main menu in the split view has the background that I want.
From this main menu, I 3 other UITableViewController sublasses that are pushed onto the nav controller when I select the relevant rows. I cannot however get the background of these tables to change using the appearance proxy. I'm trying the following :
UIImageView *bgView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"menuBg.png"]] autorelease];
[[UITableView appearanceWhenContainedIn:[PBTwitterTableViewController class], nil] setBackgroundView:bgView];
This is also in the appDelegate right below the code previously shown that works (without the repetition of the image view creation however) but this simply does nothing! When I push an instance of the PBTwitterTableViewController onto the nav controller, I simply get a standard table view with no background change.
I know that I could simply change the background views in the tableViewControllers themselves, however I don't want these backgrounds to be there when the menu is shown in the splitViewControllers popover when rotated to portait, hence I am trying to use appearanceWhenContainedIn:
I also don't want to simply set the appearance to be when contained in the UISplitViewController, as in 2 instances I have a UITableView being loaded into the detail section, so this would then change the appearance of those which I do not want.
Is there another way of doing this without the appearance proxy that will still allow me to change the background for when it is in the popover, or is there a way of making this work with the proxy, or am I just missing something stupid?
Thanks
EDIT :
I've just tried creating a subclass of the UINavigationController and tried using [[UITableView appearanceWhenContainedIn:[PBMenuNavigationController class], nil] setBackgroundView:bgView]; which is again working fine for the main menu, but not for any other UITableView pushed onto the stack, so I'm really stumped now :(

OK sorted it. Just doing it inside each view and checking that the parent controller isn't something that I don't want. Thanks anyway

Related

Problem with UIPopOverController shrinking in width when navigationController pushes a new view(screenshots included)

Ok I have a view that we will call homeView. When a certain button is pushed on homeView, a UIPopOverController is presented in the following way:
self.studyPicker = [[[StudyPickerController alloc] initWithStudyArray:self.studyArray ViewNum:butto.tag] autorelease];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.studyPicker];
_studyPicker.delegate = self;
self.studyPickerPopover = [[[UIPopoverController alloc] initWithContentViewController:navController] autorelease];
[self.studyPickerPopover presentPopoverFromRect:CGRectMake(955,60, 22,10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Which works great. I get a nice big popover controller that displays my tableView data just the way I need it. Just as an FYI, in my StudyPickerController viewDidLoad method, I am also setting this:
self.contentSizeForViewInPopover = CGSizeMake(1000.0, 610.0);
Which allows me to make the size of my tableView nice and big. The problem I am experiencing is after I select a row in this first tableView. The navigationController pushes the new view just fine, but then the width of my popover controller gets cut in half! It doesn't make any sense! I have tried everything and can't figure out what is going on. In the new view, called ScreenView, it also has the same code in viewDidLoad:
self.contentSizeForViewInPopover = CGSizeMake(1000.0, 610.0);
An interesting observation that I've made but don't know what to do with is that if I take out the contentForSize code from the Second view in the tableView, or the one that I am trying to push to within the controller, when it pushes, it gets cut in half again, to the width of a standard popover controller you see in like Safari. But adding that code in makes it 2 times as wide, like there are two glued together or something, but it is still more narrow than the original width.
I don't know what's going on here, hopefully someone can help me out!
Thanks
Here is an image of the width it should stay:
And then here it is after it pushes the new view:
For each view you are presenting in the UIPopoverController, set the property
contentSizeForViewInPopover
For example:
myViewController.contentSizeForViewInPopover = CGSize(120.0f, 320.0f);
You will need to account for the size of the UINavigationBar (that you get from the UINavigationBar) inside the UIPopoverController but overall that controls the stretching and contracting of the UIPopoverController.

Access everywhere to an UIImageView added under UIWindow

In my app start delegate I have the following code:
[window addSubview:[myTabBarController view]];
UIImageView *banner =
[[[UIImageView alloc] initWithFrame:CGRectMake(0,381,320,50)] autorelease];
banner.backgroundColor = [UIColor redColor];
[window addSubview:banner];
[window makeKeyAndVisible];
This works as expected. The tab bar is visible and also my UIImageView is visible.
I need to modify that UIImageView everywhere in my app (I have the TabBarController, a NavigationController, UITableView, etc)
For example, I want to change the background color when I click in a UITableCell.
I tried everything: self.window.view.subviews, atObjectIndex, neither seems to get the current background color.
first you do not need an UIImageView if its just to set a background-color. A UIView is sufficient.
to solve your problem, you can keep a reference to the view who's background-color you want to change in you AppDelegate. you can then access you AppDelegate (and the the reference to your view) from anywhere in your app like so:
((YouAppDelegateName*)[UIApplication sharedApplication].delegate).yourViewReferenceProperty
Are you sure you want to do that?
It's usually best to arrange your app so that the only object manipulating a view controller's view hierarchy is that view controller. If other objects want to change something, they either change the data model or send a message to the view controller. So, you might give your view controller a 'backgroundColor' property, and its setter would update the appropriate view. Setting the background color indirectly through the view controller makes it easier to make changes to your view hierarchy in the future and generally keeps things better organized.

NavigationBar don't have to scroll with UITable

I'm developing an iPhone app. I'm using a UITable subclassing UITableViewController. I added a NavigationBar to the view: UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 320.0f, 48.0f)];[self.tableView addSubview:navBar];, now the problem is that the navigation bar scroll down with the table and it's what I want to avoid. Is possible to avoid it using the UITableViewController?
You say
I'm using a UITable subclassing UITableViewController
I guess you are using a subclassed UITableViewController which, naturally, holds a UITableView.
Your problem is caused by the fact, that you inserted the NavigationBar into the UITableView, or, more precisely, into the UIScrollView which is part of the TableView.
Depending on your needs, you have two options:
If you want your app to behave like e.g. Mail (so your TableView will be just one element in a structure of views, through which you can dig down), you should a UINavigationcontroller and make your TableViewController the NavigationController's first view, like when you open the "Navigation based"-Template in Xcode. The UINavigationcontroller will already contain a UINavigationBar, so there isn't much you have to worry about.
If, for some reason, that's not what you want, you will have to create a UIView which holds your UINavigationBar as well as the UITableView. Since accomplishing such a setup with a UITableViewController is known to be rather difficult, you might want to ditch your TableViewController and replace it with a simple ViewController, which implements both the "UITableViewDelegate"- and "UITableViewDataSource"-Delegate. See this post for further help.

How do I reduce the height of a TableView when it is constructed in IB?

I wanted to add a view to the bottom of my screen. The controller is a UITableViewController, how do I shrink the tableView and add a extra view at the bottom of the tableview?
I've tried setting the frame of self.tableView in different places (viewDidLoad, viewWillAppear etc) but nothing happens. The tableView is created by IB and not programtically.
I've tried added a footer to my table view but that's not what I want, because the footer actually scrolls up, I want a static non moving View at the bottom of the screen.
I'm not saying you can't do it otherwise, but you may not want a UITableViewController for this situation. You can still have your view controller implement UITableViewDelegate and UITableViewDataSource, but place a vanilla UIView in your nib, into which you place a UITableView. Then just make sure to set the view outlet to the UIView containing your table. This has the effect of allowing you to create your additional view within IB. I just tried this and it appeared to work.
I'm guessing you're using a UINavigationController. When you push a controller onto your navigation stack, UINavigationController resizes its view to full screen, ignoring the geometry and autoresizing behavior you've defined in IB.
This resizing seems to happen after viewWillAppear:. In the past I've had some success resizing a table view and adding a sibling view in viewDidAppear:, after calling [super viewDidAppear:]. This is a bit risky though, since Apple could break it by changing how UINavigationController works behind the scenes.
A safer option is to push a view controller onto your navigation stack that controls a wrapper view. Then add your UITableView and its sibling as subviews of that wrapper view. The annoying thing about this option is that you'll probably want to use a nested UITableViewController to manage your non-full screen table view, but the documentation for UIViewController says it's designed to manage full screen views only. If you decide to ignore this admonition and nest your view controllers anyway, you'll find that viewWill/DidAppear/Disappear don't get called on the nested controller, so you'll have to manually delegate those methods from your wrapper view controller. This lack of support for nested controllers is one of my biggest pet peeves about UIKit, and I've gone to great lengths to engineer around it.
If you want to toe the line and use view controllers only for full screen views, you can push a normal view controller that controls your full screen wrapper view, manually implement all the UITableViewDataSource and UITableViewDelegate methods in your view controller, and set it as the delegate for your table view.
you want to change the -loadView method. Not viewDidLoad or viewWillAppear. This will allow you to make additional configurations with your tableview even if it is created in IB.
- (void)loadView {
[super loadView];
CGRect titleRect = CGRectMake(0, 0, 300, 40);
UILabel *tableTitle = [[UILabel alloc] initWithFrame:titleRect];
tableTitle.textColor = [UIColor blueColor];
tableTitle.backgroundColor = [self.tableView backgroundColor];
tableTitle.opaque = YES;
tableTitle.font = [UIFont boldSystemFontOfSize:18];
tableTitle.text = [curTrail objectForKey:#"Name"];
self.tableView.tableHeaderView = tableTitle;
[self.tableView reloadData];
[tableTitle release];
}
I don't know how to do it in IB but the way to do it in code is with this:
- (void) loadView
{
UITableView *tv = [[UITableView alloc] initWithFrame: rect
style: UITableViewStyleGrouped];
// finishg configuring table view
self.view = tv;
[tv release];
}
Trying to do it in two stages -- style first and then frame or frame first and then style -- neither of them works.

Using IB to add a UISegmentedControl to a NavigationBar

I'm current creating a UISegmentedControl programmatically in a view controller's viewDidLoad method and adding it to the view controller's navigation bar by assigning it to self.navigationItem.titleView.
That's easy enough, but I'd like to be able to do this in Interface Builder as well and so far haven't been able to figure out how. Google hasn't been much help either. Can someone describe how to do this in IB or point to an online example? I'd be much appreciative.
Thanks,
Howard
If you've got whole nav stack in the nib, it's actually pretty easy; you can just drag it into the title area and IB does the right thing automatically.
Otherwise, you can just add the segmented control to the nib (not necessarily a subview) and then add an #property IBOutlet to it from your view controller. Then in viewDidLoad, assign it to the titleView as normal. Remember to release in dealloc, and you're golden.
In IB you certainly can just drag a view into the middle of the navigation controller and it will work fine if its just inside one navigation item.
However, if the same view object reference is dragged into the title view area of different navigation items that will at some point be pushed onto the navigation controllers stack, you will run into problems with the title view disappearing when you travel back through the stack. The navigation controller isn't too happy with references to the same object popping up on multiple navigation items for some reason and it only throws a fit when you pop back to the view with the troublesome navigation item.
To get around this you MUST explicitly set and unset the titleView object when the you navigate to the views using the shared title view object reference. For instance, if you had custom logic behind a subclassed view set as the titleView that you only wanted to instantiate once.
Alternatively, you could store the UISegmentedControl designed in IB in it's own NIB. Then set the FileOwner to the viewcontroller class that will be using the segmentedControl instance. In the viewcontroller class, declare the segmentedcontrol as an IBOutlet Property and link it to the instance in the nib.
All left to using the designed instance is then to call:
[[NSBundle mainBundle] loadNibNamed:#"TTCustomSegmentedControl"
owner:self
options:nil];
self.navigationItem.titleView = sortSegmentControl;
Just try this (works for me):
UISegmentedControl *mSegmentedControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:
#"Segment 1",
#"Segment 2",
nil]];
mSegmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
mSegmentedControl.tintColor = [UIColor redColor];
[mSegmentedControl setSelectedSegmentIndex:0];
[mSegmentedControl addTarget:self action:#selector(sectionPress:)
forControlEvents:UIControlEventValueChanged];
self.navigationItem.titleView = mSegmentedControl;
You can't set the titleView property in IB, but you may be able to create / set up the control as a child of your controller's view via Interface Builder, and then in your viewDidLoad method, remove it from your view and set it as the titleView:
[segControl removeFromSuperview];
self.navigationItem.titleView = segControl;