self.tabBarController setSelectedIndex: not working - ios6

Things in the project:
a storyboard which contains just one Tab Bar Controller and four view controllers (so I have four tab bar items, and four segues, very very simple)
a custom Obj-Class which is used by the Tab Bar Controller, and draw a button on the "self.view"
What's the problem:
want to simulate "pressing the tab bar item" but not it is not working. help please. (I have not any other custom-obj-class but the only one for the UITabBarController)
What I've tried:
[(UITabBarController*)self.navigationController.topViewController setSelectedIndex:3];
[self.tabBarController setSelectedIndex:3];
[self.tabBarController setSelectedController
[self.tabBarController setSelectedViewController:[self.tabBarController.viewControllers objectAtIndex:3]];
custom-obj-class.m :
- (IBAction)buttonPressed:(UIButton *)sender
{
if (self.tabBarController) {
NSLog(#"I have a tab bar");
[self.tabBarController setSelectedIndex:1];
} else {
NSLog(#"I don't have"); // I GOT THIS ONE
}
return;
}
- (void)viewDidLoad
{
[super viewDidLoad];
...
UIBarButtonItem *realRoomItem = [[UIBarButtonItem alloc] initWithImage:realRoomImage style:UIBarButtonItemStylePlain target:self action:#selector(buttonPressed:)];
...
}

I'm sorry, there's a big mistake. It should be "self" but not "self.tabBarController" since my custom-obj-class is the class of UITabBarController and used in it also.

Related

How to dismiss a popover in iPhone 5 iOS 6?

When my iPhone 5 app starts up I present no view controller because of the following:
- (void) viewDidAppear:(BOOL)animated {
}
The first thing the user will do is touch a button that is on the initial screen
that opens up a menu for retrieving a picture either from the user's
photo library, camera, or a picture of obama. The method that is called when that button is touched by the user is:
- (IBAction) pickImage {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Image Source"
delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil
otherButtonTitles:#"Photo Library", #"Camera", #"Obama", nil];
[actionSheet showInView:scrollView];
[actionSheet release];
}
Now the actionSheet eventually calls:
[self presentViewController:imagePicker animated:TRUE completion:nil];
For the iPhone 5 everything works and the user is given 3 options with the presentViewController. After the user picks an image then I call:
[[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
and the View Controller goes away. Now what I WOULD LIKE TO DO IS make the view controller appear initially so the user doesn't have to touch the button connected to pickImage by adding a line to the viewDidAppear method like so:
- (void) viewDidAppear:(BOOL)animated {
[self pickImage]; // makes the image picker pop up when app intializes
}
HOWEVER, when I test this, the imagePicker automatically appears like I expected but then after I finish picking my image and dismiss it, it reappears after I have chosen my image. HOW CAN I FIX THIS???
The following is the class I am talking about:
MainViewController.h FILE: http://db.tt/Vgm3w0gs
MainViewController.m FILE: http://db.tt/uN8YdNGN
Or you can just look at the following relevant methods:
- (void) actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0: { //photo library
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imagePicker animated:TRUE completion:nil];
} else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Photo library is empty or unavailable" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
break;
}
case 1: //camera option has it's view controller dismissed after image is taken. The rest of ActionSheet doesn't really matter...
HERE is the method that dismisses the ViewController except when imagePicker is called from within viewDidAppear. QUESTION: How can I get the viewController to dismiss when imagePicker is called from within viewDidAppear?
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// loads image into main screen
[self loadImage:[info objectForKey:UIImagePickerControllerOriginalImage]];
[[picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
} [picker release];
}
Your current problem seems to be that you want pickImage to be called when the view first appears, but not when it reappears as a result of a popup window closing.
One possibilty would be to move the pickImage call from the viewDidAppear callback into the viewDidLoad callback.
However, if that is being called too soon, the other option would be to add a boolean variable that you check in viewDidAppear to make sure that pickImage is only called once.
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (firstAppearance) {
firstAppearance = NO;
[self pickImage];
}
}
And set that boolean to true in the viewDidLoad callback.
- (void) viewDidLoad {
[super viewDidLoad];
firstAppearance = YES;
}
Obviously you would also need to declare the bool in your header file somewhere.
BOOL firstAppearance;

How to figure out use a modal segue instead of push segue

I have this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segueFotosAloj"]) {
localGallery = [[FGalleryViewController alloc] initWithPhotoSource:self];
[self.navigationController pushViewController:localGallery animated:YES];
}
I want to use modal segues, so I can't have a PushViewController statement if I remove that line the Gallery don't load the images, how can I do it use a modal segue? (I don't want use push segue because I'm getting some errors about the navigationcontroller stack)
Here is an example code for modal segue. Just change the name of the view controller to the name of the view controller you are using in your project.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segueFotosAloj"])
{
SomeViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SomeIdentifier"];
[self.navigationController presentViewController:controller animated:YES completion:nil];
}
}
P.s, someViewController is the name you have to change.

iOs 6 return from UIViewController in landscape to portrait

So I have an application with navigation controller, the last one viewcontoller can be rotated to any orientation. And the others must be in portrait only. So I have troubles when we rotate the last viewController in landscape and then pressing back button on navigation controller. We go to previous one and see that layout are broken.
I thought the only way is to use something like this:
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait]
(I know it's a hack and it would be preferred to avoid such things)
But wherever I tried it - it caused me with different layout problems. The usual methods like:
- (NSUInteger)supportedInterfaceOrientations
- (BOOL)shouldAutorotate
and so on for handle orientation are useless in this situation.
Thanks in advance.
I solved this problem for parent of those viewControllers who must be in portrait:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
}
For rotation viewController:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
For Navigation Controller:
- (BOOL)shouldAutorotate {
BOOL result = self.topViewController.shouldAutorotate;
return result;
}
- (NSUInteger)supportedInterfaceOrientations {
NSUInteger result = self.topViewController.supportedInterfaceOrientations;
return result;
}
And added this to AppDelegate:
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
if ([navigationController.topViewController isKindOfClass:[RotationViewController class]])
return UIInterfaceOrientationMaskAll;
else
return UIInterfaceOrientationMaskPortrait;
}

Unable to change color of UISearchDisplayController

I'm using UISearchDisplayControlleron UInavigationBar but the background color of UISearchDisplayController is not matching the color of uinavigationbar. i used the following code in ma ViewDidLoad but no change I'm unable to change the color of UISearchDisplayController
self.searchDisplayController.searchBar.tintColor = [UIColor clearColor];
A UISearchDisplayController is not an interface element. It is a controller, not a view. It has no color.
What I did was I created a UISearchBar subclass and in IB made the searchBar belonging to the UISearchDisplayController part of that subclass. From there I was able to change the tintColor and backgroundColor. The reason I needed this was because the UISearchBar was not displaying correctly within a UINavigationBar and this was the only way I could think of on, how to do it.
Edit
Your actually able to do this relatively easy with UISearchDisplayController's initializer, initWithSearchBar:contentsController:, however you'll still need to subclass UISearchBar.
Here is the Code I used. Now if your performing this through IB you only need to use initWithCoder: but I created a setup method. Just incase, I need to use it again, in places other than IB.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self setup];
}
return self;
}
-(id) initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self setup];
}
return self;
}
-(id)init {
if (self = [super init]) {
[self setup];
}
return self;
}
-(void) setup {
self.backgroundColor = [UIColor clearColor];
self.tintColor = [UIColor clearColor];
for (UIView * view in self.subviews) {
if ([view isMemberOfClass:NSClassFromString(#"UISearchBarBackground")]) {
view.alpha = 0.0;
}
}
}

iOS 6 landscape and portrait orientation

I have a table with a big list of stuff that comes from a plist file and clicking each of them takes you to a new view, a xib.
I have 2 views inside that .xib, one for portrait and one for landscape
In my h file I have this:
IBOutlet UIView *portraitView;
IBOutlet UIView *landscapeView;
#property (nonatomic, retain) IBOutlet UIView *portraitView;
#property (nonatomic, retain) IBOutlet UIView *landscapeView;
In my m file this:
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
- (void) orientationChanged:(id)object
{
UIInterfaceOrientation interfaceOrientation = [[object object] orientation];
if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
self.view = self.portraitView;
}
else
{
self.view = self.landscapeView;
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
self.view = portraitView;
} else if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
self.view = landscapeView;
}
return YES;
}
#end
Everything was working perfectly in iOS 5, showing landscape or portrait when needed.
Now with the iOS 6 update everything is a mess.
If I am in the table (portrait) view and click one item, it shows correct in portrait, if I rotate to landscape, the view shows the correct view as well, BUT being in landscape, if I go back to the table and select another item, it shows the portrait view instead of the landscape.
If I do the same but starting landscape, it shows portrait.
So, now the orientation is not working for anything.
The same happens to my other views using storyboard. They are portrait and always showed like that, now they rotate, shrink everything and leave my app as trash.
1- How can I fix the .xib orientation thing ?
2- How can I fix the storyboard orientation ? (they were static, now everything rotates (no code at all))
Thanks.
I think that I have a work around. It's ugly but it's working...
With iOS6 Apple suggest now to use 2 differences XIB file to switch between portrait & landscape view.
But if you want to use the previous method allowed in iOS 5.0 by "switching" between 2 UIView IBOutlet, you can try my ugly working solution. The idea is to rotate the view according to the orientation.
1) In you viewDidLoad, subscribe to orientation notification:
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
2) Add a method called by the notification:
-(void)orientationChanged:(NSNotification *)object{
NSLog(#"orientation change");
UIDeviceOrientation deviceOrientation = [[object object] orientation];
if(deviceOrientation == UIInterfaceOrientationPortrait || deviceOrientation == UIInterfaceOrientationPortraitUpsideDown){
self.view = self.potraitView;
if(deviceOrientation ==UIInterfaceOrientationPortraitUpsideDown){
NSLog(#"Changed Orientation To PortraitUpsideDown");
[self portraitUpsideDownOrientation];
}else{
NSLog(#"Changed Orientation To Portrait");
[self portraitOrientation];
}
}else{
self.view = self.landscapeView;
if(deviceOrientation ==UIInterfaceOrientationLandscapeLeft){
NSLog(#"Changed Orientation To Landscape left");
[self landscapeLeftOrientation];
}else{
NSLog(#"Changed Orientation To Landscape right");
[self landscapeRightOrientation];
}
}
}
3) And finally, add rotation method for each orientation:
-(void)landscapeLeftOrientation{
// Rotates the view.
CGAffineTransform transform = CGAffineTransformMakeRotation(-(3.14159/2));
self.view.transform = transform;
// Repositions and resizes the view.
CGRect contentRect = CGRectMake(0, 0, 480, 320);
self.view.bounds = contentRect;
}
-(void)landscapeRightOrientation{
// Rotates the view.
CGAffineTransform transform = CGAffineTransformMakeRotation(3.14159/2);
self.view.transform = transform;
// Repositions and resizes the view.
CGRect contentRect = CGRectMake(0, 0, 480, 320);
self.view.bounds = contentRect;
}
-(void)portraitOrientation{
// Rotates the view.
CGAffineTransform transform = CGAffineTransformMakeRotation(0);
self.view.transform = transform;
// Repositions and resizes the view.
CGRect contentRect = CGRectMake(0, 0, 320, 480);
self.view.bounds = contentRect;
}
-(void)portraitUpsideDownOrientation{
// Rotates the view.
CGAffineTransform transform = CGAffineTransformMakeRotation(3.14159);
self.view.transform = transform;
// Repositions and resizes the view.
CGRect contentRect = CGRectMake(0, 0, 320, 480);
self.view.bounds = contentRect;
}
I suggest you to make a custom UIViewController class and inherit-ate from this class to save redundant code.
If you want to support both solution for ios5 and ios6 you can use a #endif macro to include the both code in your controllers.
Cheers
No need to send and receive notifications:
In your appdelegate.m the following method
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
is always called to check the window's orientation,
so a simple way around is to have the below described code in your appdelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
if(self.window.rootViewController){
UIViewController *presentedViewController ;
if ([self.window.rootViewController isKindOfClass:([UINavigationController class])])
{
presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
}
else if ([self.window.rootViewController isKindOfClass:[UITabBarController class]]){
UITabBarController *controller = (UITabBarController*)self.window.rootViewController;
id selectedController = [controller presentedViewController];
if (!selectedController) {
selectedController = [controller selectedViewController];
}
if ([selectedController isKindOfClass:([UINavigationController class])])
{
presentedViewController = [[(UINavigationController *)selectedController viewControllers] lastObject];
}
else{
presentedViewController = selectedController;
}
}
else
{
presentedViewController = self.window.rootViewController;
}
if ([presentedViewController respondsToSelector:#selector(supportedInterfaceOrientations)]) {
orientations = [presentedViewController supportedInterfaceOrientations];
}
}
return orientations;
}
and implement
- (NSUInteger)supportedInterfaceOrientations
in the respective view controllers
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait; //Or anyother orientation of your choice
}
and to perform sudden action against orientation changes, implement the following method
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
This is very late for an answer, still I thought I should share this with you just in case,
I had the very same issue.
shouldAutorotateToInterfaceOrientation is deprecated iOS 6 onwards.
You need to parallel this method with the new supportedInterfaceOrientations and shouldAutorotate methods.
And it is very very important, you need to make sure that you set the root controller in your app delegate's applicationDidFinishLaunching method rather than simply adding the view controller's view ( or navigation Controller or tabBar Controller depending on what you are using ) as a subview to the window.

Resources