UIImagePickerController with cameraOverlayView on iPad iOS 6 has no "Take Photo" button - uiimagepickercontroller

The following code creates a popover controller with a UIImagePickerController that uses cameraOverlayView to show a custom button that opens photo library.
This works great on iOS 5, but on iOS 6 the "Take Photo" button is missing, instead - there's another switch between front and back camera button!
See the following screenshot -
This is the code -
UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
if ( ![UIImagePickerController isSourceTypeAvailable: sourceType] ) {
[self openLibrary: sender];
return;
}
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = sourceType;
UIButton *libraryButton = [UIButton buttonWithType: UIButtonTypeCustom];
libraryButton.frame = CGRectMake(12, 12, self.photoLibraryIcon.size.width, self.photoLibraryIcon.size.height);
[libraryButton setImage: self.photoLibraryIcon forState: UIControlStateNormal];
[libraryButton addTarget: self action: #selector(openLibrary:) forControlEvents: UIControlEventTouchUpInside];
[picker.cameraOverlayView addSubview:libraryButton];
__imagePickerPopoverController = [[UIPopoverController alloc] initWithContentViewController: picker];
self.imagePickerPopoverController.delegate = self;
[self.imagePickerPopoverController presentPopoverFromRect: CGRectMake(self.center.x - 5, self.center.y - 5, 10, 10)
inView: self.superview
permittedArrowDirections: UIPopoverArrowDirectionAny
animated: YES];
If I remove the [picker.cameraOverlayView addSubview:libraryButton], it works fine, but then my custom button will be gone (as expected).
So why assigning a cameraOverlayView changes the bottom toolbar?
Any clue on how to get the "Take Photo" button back to iOS 6?

Related

Popover button not showing in split view app

I have a split view app that should show a menu button when the device is in portrait orientation and the Master view is hidden.
When the app launches in portrait mode, this function is executed:
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc {
barButtonItem.title = #"Menu";
self.popoverController = pc;
self.rootPopoverButtonItem = barButtonItem;
// Get current detail view (splitVC-->detailNavVC-->currentVC).
UINavigationController *detailNav = [self.splitController.viewControllers objectAtIndex: 1];
UIViewController <SubstitutableDetailViewController> *detailViewController = [detailNav.viewControllers objectAtIndex: 0];
[detailViewController showRootPopoverButtonItem: rootPopoverButtonItem];
}
This function in turn launches the function in TitleViewController.m:
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray insertObject: barButtonItem atIndex: 0];
[toolbar setItems:itemsArray animated:NO];
}
All of this code seems to run correctly, but no menu button is showing. Any ideas? Thanks.
I seemed to have solved the problem by adding the following line after setting the toolbar items:
[self.view reloadInputViews];

Implementing a UISplitViewController Master Detail Application - UIPopOverController is null until rotation.

I am trying to implement a simple UISplitViewController where when in portrait mode the master view is hidden and appears with a button in a popover.
My AppDelegate is set up like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after app launch.
self.splitViewController =[[UISplitViewController alloc]init];
self.rootViewController=[[RootViewController alloc]init];
self.detailViewController=[[FirstDetailViewController alloc]init];
UINavigationController *rootNav=[[UINavigationController alloc]initWithRootViewController:rootViewController];
UINavigationController *detailNav=[[UINavigationController alloc]initWithRootViewController:detailViewController];
self.splitViewController.viewControllers=[NSArray arrayWithObjects:rootNav,detailNav,nil];
self.splitViewController.delegate=self.detailViewController;
splitViewController.presentsWithGesture = NO;
// Add the split view controller's view to the window and display.
[self.window setRootViewController:self.splitViewController];
[window makeKeyAndVisible];
return YES;
}
in FirstDetailViewController I set up a button like this:
UIImage *buttonImage = [UIImage imageNamed:#"button-menu.png"];
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
[aButton setImage:buttonImage forState:UIControlStateNormal];
aButton.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
[aButton addTarget:self action:#selector(showNavigation) forControlEvents:UIControlEventTouchUpInside];
aBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:aButton];
self.appDelegate.rootPopoverButtonItem = aBarButtonItem;
showNavigation looks like this:
-(void)showNavigation{
NSLog(#"I am in show navigation and pc=%#",self.popoverController);
[self.popoverController presentPopoverFromRect:self.view.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
When I initially load the app and press the button I get an NSLog of
I am in show navigation and pc=(null)
And the pop over dosen't show. Now when I rotate the device to landscape mode, and then back to portrait, the master view hides and shows as expected, and the button now works in portrait mode.
Here is the code that handles the rotation:
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc {
[[self navigationItem] setLeftBarButtonItem:aBarButtonItem];
[self setPopoverController:pc];
self.appDelegate.rootPopoverButtonItem = aBarButtonItem;
}
// Called when the view is shown again in the split view, invalidating the button and popover controller.
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
[[self navigationItem] setLeftBarButtonItem:nil];
[self setPopoverController:nil];
self.appDelegate.rootPopoverButtonItem = aBarButtonItem;
}
How do I get the popovercontroller to not be null before any rotation occurs?
Ok turns out I had an if in my willHideViewController which did not include the [self setPopoverController:pc]; line. duh!

In RootViewController my UIBarButtonItem disappears when using UITableViewStyleGrouped

I'm using a split view for an iPad app.
In my RootViewController.m file I assign two UIBarButtonItems like this
- (void)viewDidLoad
{
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 300.0);
// add a save button
saveButton = [[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self action:#selector(saveAction:)] autorelease];
self.navigationItem.rightBarButtonItem = saveButton;
// add a cancel button
cancelButton = [[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:#selector(cancelAction:)] autorelease];
self.navigationItem.leftBarButtonItem = cancelButton;
}
These buttons show up nicely when I use UITableViewStylePlain styling for the table view. But if I use UITableViewStyleGrouped, then the buttons disappear. Here is how I set my grouped style
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithStyle:UITableViewStyleGrouped];
return self;
}
Regardless of the presence or absence of the buttons, the size of the header remains the same.
I'm clueless as to why this happening.
all help greatly appreciated
Dhoti

Override back button in navigation stack while keeping appearance of default back button?

How do I override the back button for just one view (not for all the back buttons present in different views) such that on click of the back button, the root view controller is shown?
You need to replace the backbutton and associate an action handler:
- (void)viewDidLoad {
[super viewDidLoad];
// change the back button to cancel and add an event handler
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#”back”
style:UIBarButtonItemStyleBordered
target:self
action:#selector(handleBack:)];
self.navigationItem.leftBarButtonItem = backButton;
}
- (void)handleBack:(id)sender {
// pop to root view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
Found a solution which retains the back button style as well.
Add the following method to your view controller.
-(void) overrideBack{
UIButton *transparentButton = [[UIButton alloc] init];
[transparentButton setFrame:CGRectMake(0,0, 50, 40)];
[transparentButton setBackgroundColor:[UIColor clearColor]];
[transparentButton addTarget:self action:#selector(backAction:) forControlEvents:UIControlEventTouchUpInside];
[self.navigationController.navigationBar addSubview:transparentButton];
}
Now provide a functionality as needed in the following method:
-(void)backAction:(UIBarButtonItem *)sender {
//Your functionality
}
All it does is to cover the back button with a transparent button ;)
It's old, but the correct answer is that:
Instead of pushing your ViewController on top of all the others, you'd better replace the full stack with the rootVC and the new VC only.
Not:
self.navigationController?.pushViewController(myVc, animated: true)
But:
let vcStack = self.navigationController?.viewControllers
self.navigationController?.setViewControllers([vcStack![0],myVc], animated: true)
Like that, on back it will just popToRoot because it's the previous viewController in stack
I had the similar problem and I successfully used the answer given by Sarasranglt. Here is the SWIFT version.
override func viewDidLoad() {
let transparentButton = UIButton()
transparentButton.frame = CGRectMake(0, 0, 50, 40)
transparentButton.backgroundColor = UIColor.orangeColor()
transparentButton.addTarget(self, action:"backAction:", forControlEvents:.TouchUpInside)
self.navigationController?.navigationBar.addSubview(transparentButton)
}
And the function is
func backAction(sender:UIButton) {
// Some sction
}
Another approach is to adopt UINavigationControllerDelegate Protocol.
– navigationController:willShowViewController:animated:
– navigationController:didShowViewController:animated:
Those methods will let you know when a controller appears but you have to check that controller is the controller you want.
For keeping same appearance you can use :
UIView *leftButtonView = [[UIView alloc]initWithFrame:CGRectMake(-12, 0, 105, 30)];
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeSystem];
leftButton.frame = leftButtonView.frame;
[leftButton setImage:[UIImage imageNamed:#"ic_system_back"] forState:UIControlStateNormal];
[leftButton setTitle:#"title" forState:UIControlStateNormal];
[leftButton.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[leftButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
[leftButton setTitleEdgeInsets: UIEdgeInsetsMake(0, 8, 0, 0)];
[leftButton addTarget:self action:#selector(handleBack:) forControlEvents:UIControlEventTouchUpInside];
[leftButtonView addSubview:leftButton];
UIBarButtonItem *leftBarButton = [[UIBarButtonItem alloc]initWithCustomView:leftButtonView];
self.navigationItem.leftBarButtonItem = leftBarButton;
Following Sarasranglt's method of having a transparent button, in objective C, and Pavle Mijatovic's earlier swift version, here is a swift 4 version:
let transparentButton = UIButton()
transparentButton.frame = CGRect(x:0, y:0, width:50, height: 40)
transparentButton.backgroundColor = UIColor.clear
transparentButton.addTarget(self, action:#selector(backAction(sender:)), for:.touchUpInside)
self.navigationController?.navigationBar.addSubview(transparentButton)
and
#objc func backAction(sender:UIButton) {
// Some action
}
without making custom button or without any hack(transparentButton) just override 'viewWillDisappear' method and write your code inside the block.
override func viewWillDisappear(_ animated: Bool) {
// write your code...
}
The following code (written in C# for Xamarin iOS) will replace the back button with a custom one that looks just like the system implementation (chevron icon included).
The system "back" navigation will no longer fire, and you are free to handle the TouchUpInside as you wish.
Converting it to ObjC shouldn't take long, I'll leave that fun to you :)
var backButton = new UIButton(new CGRect(0, 0, 70.0, 70.0));
var symbolCfg = UIImageSymbolConfiguration.Create(UIFont.ButtonFontSize, UIImageSymbolWeight.Bold, UIImageSymbolScale.Large)
var backImage = UIImage.GetSystemImage("chevron.left", symbolCfg);
backButton.SetImage(backImage, forState: UIControlState.Normal);
backButton.TitleEdgeInsets = new UIEdgeInsets(10.0f, 10.0f, 10.0f, 0.0f);
backButton.SetTitle("Back", forState: UIControlState.Normal);
var backBarButton = new UIBarButtonItem(customView: backButton);
NavigationItem.LeftBarButtonItems = new[] { backBarButton };
Use this code to show a custom back button, Note the backBarButtonItem before marking it as a duplicate answer.
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"< back"
style:UIBarButtonItemStylePlain
target:self
action:#selector(handleBack:)];
self.navigationItem.backBarButtonItem= backButton;
Cheers!

uinavigationController's toolbar with custom items

I am trying to use the NavigationController's toolbar in my app. This toolbar's toolbarItems are suppose to change depending on which view controller is presented. this is very basic.
What I am trying to do is to add custom buttons to the toolbar using the UIBarButtonItem's "initWithCustomView:" method. However, the button won't show up on the toolbar. But if I create the UIBarButtonItem using the "initWithTitle:" or "initWithBarButtonSystemItem:" method, the button show up. For example, look at the code below:
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks target:self action:nil];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:#"edit" style:UIBarButtonItemStylePlain target:self action:nil];
NSArray *array = [[NSArray alloc] initWithObjects:item1, item2, nil];
[self setToolbarItems:array];
If this is done, buttons show up on the toolbar. But, if I were to do the following:
UIButton* replyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[replyBtn setImage:[UIImage imageNamed:#"Reply_Message.png"] forState:UIControlStateNormal];
[replyBtn addTarget:self action:#selector(replyButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
replyBtn.frame = CGRectMake(10, 0, 40, 40);
UIBarButtonItem *replyButton = [[UIBarButtonItem alloc] initWithCustomView:replyBtn];
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks target:self action:nil];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:#"edit" style:UIBarButtonItemStylePlain target:self action:nil];
NSArray *array = [[NSArray alloc] initWithObjects:item1, replyButton, item2, nil];
[self setToolbarItems:array];
In this code, only the item1 and item2 are displayed on the toolbar. replyButton is not shown on the toolbar. There is blank space at the place where the button is suppose to be at.
If this same code used on a regular toolbar that I create instead of NavigationController's toolbar, the button shows up. I am trying to just use one toolbar throughout the app to have the same feel that Apple's Mail application does. The reason that I need to use the "initWithCustomView:" method is because one of the icons is colored and this is the only way it shows up colored on a normal toolbar. Now, I have looked through apple documentation and there isn't any mention of why the "initWithCustomView:" method couldn't be called (or maybe I couldn't find it).
Could please somebody shine some light on this topic to help me point in the right direction. thanks in advance guys.
I can't see the difference from what you tried, but it eventually worked for me, with that code:
//////////////////////////////////////////////////////////////////////////////////////////////
/////>>>> Adding buttons for browsing in the toolbar of the popover's navigation controller///
//////////////////////////////////////////////////////////////////////////////////////////////
//>>>>Create a goBack button
goBack = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *goBackImage = [UIImage imageNamed:#"back1.png"];
[goBack setImage:goBackImage forState:UIControlStateNormal];
[goBack addTarget:self action:#selector(goBackClicked:) forControlEvents:UIControlEventTouchUpInside];
goBack.frame = CGRectMake(0,0,goBackImage.size.width,goBackImage.size.height);
//Create a Bar button to hold this button
UIBarButtonItem *goBackBarButton = [[[UIBarButtonItem alloc] initWithCustomView:goBack] autorelease];
UIBarButtonItem *flex1 = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease];
UIBarButtonItem *addButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind target:nil action:nil] autorelease];
NSArray *arrayOfButtons = [[[NSArray alloc] initWithObjects:goBackBarButton, flex1, addButton, nil] autorelease];
[self setToolbarItems:arrayOfButtons];
Note few differences from yours (maybe that's where the catch? I'm not sure):
1. my buttons are not allocated locally in the method, but in the class (you know, the property, synthesize, etc)
2. yours
[replyBtn setImage:[UIImage imageNamed:#"Reply_Message.png"] forState:UIControlStateNormal];
where mine looks a bit different
[goBack setImage:goBackImage forState:UIControlStateNormal];
Try these tiny changes, maybe it will work :)
I was having the same problem. It turns out that the toolbar for the UINavigationController resets it's items every time a new view gets pushed on the stack. I was trying to set the toolbar items in the applicationDidFinish function, and it was not working. It worked once I set the toolbar itms in the - (void) viewDidAppear function of the viewController that was being pushed onto the navigation stack.
So, it seems like if you want the navigation controller to keep the same toolbar items throughout the application, you have to set the toolbar items in each view that you push onto the navigation controller after the view appears.
I hope that helps!
I'd wager a guess that the item isn't showing up because its view doesn't have anything in it. Are you sure there's an image called Reply_Message.png in your project? [UIImage imageNamed:#"Reply_Message.png"] might be nil.
You can use one toolbar throughout your app without using the navigation controllers toolbar. Since your code works with a non-navigationController toolbar, this might be the easiest way to accomplish what you want. In your app delegate, try adding a toolbar to window, like this. This way it is persistent throughout the app. Make sure you consider a scheme that will let you access the toolbar to add/remove buttons, or hide/show it from different view controllers.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/////// frame sizes ////////
// compensate for the status bar
int statusBarHeight = 20;
// toolbar
int toolbarWidth = window.frame.size.width;
int toolbarHeight = 30; // I think standard size is 30
int toolbarxOffset = 0;
int toolbaryOffset = window.frame.size.height - tHeight;
CGRect toolbarFrame = CGRectMake(toolbarxOffset,
toolbaryOffset,
toolbarWidth,
toolbarHeight);
/////// toolbar //////////////////////
self.myPersistentToolbar = [[UIToolbar alloc] initWithFrame:toolbarFrame];
[window addSubview:self.myPersistentToolbar];
}

Resources