I'm working on a tabbed application which has 5 UITabBarItem. On the second UITabBarItem I would display the photo album using an UIImagePickerController, but the result is a strange black-white screen (I will post it at bottom).
Here is my SecondViewController.h:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
#end
and SecondViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIAlertView *noLibraryAlertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"No photo library!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[noLibraryAlertView show];
} else {
self.delegate = self;
self.allowsEditing = NO;
self.navigationBarHidden = NO;
self.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
}
}
But when I select the second UITabBarItem the app shows this:
Any ideas?
Thanks in advance.
According to apple's documentation a UIImagePicker must be presented modally:
Present the user interface. On iPhone or iPod touch, do this modally (full-screen) by calling the presentViewController:animated:completion: method of the currently active view controller, passing your configured image picker controller as the new view controller.
So it won't work in a tabbarcontroller or as a child of another controller.
Officially you can't subclass UIImagePickerController.
However, assuming that you are using storyboard to instantiate SecondViewController, I found that changing the code like this would work:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// other settings
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIAlertView *noLibraryAlertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"No photo library!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[noLibraryAlertView show];
}
}
Your code wasn't working correctly because you were setting the sourceType after the view was loaded.
I'm sorry, it was a stupid problem in
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
It was an autocomplete mistake, but many thanks to all for informations about presentation and subclassing of UIImagePickerController.
Related
UIAlertView delayed or not showing up when pass another view. Any help would be greatly appreciated.
-(void)viewDidLoad{
levelContentController = [[UIAlertView alloc] initWithTitle:#""
message:#"Loading...
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
}
-(void)passToTestView:(id)sender{
[levelContentController show];
ViewController *viewController = [[ViewController alloc]init];
clickedLevelId = [[NSString alloc] init];
clickedLevelId = [testIdStringArray objectAtIndex:[sender tag]-1];
[viewController sendIndexMethod:sendIndex];
[viewController testCompletedArrayMethod:arrayOfCompletedTest];
[viewController parseTestURL:buttonTag getTestIdString:clickedLevelId];
viewController.viewSoundCheck = _levelSoundCheck;
[self presentViewController:viewController animated:YES completion:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[levelContentController dismissWithClickedButtonIndex:0 animated:YES];
}
The above code has some problems.
When passToTestView: selector is called, it'll try to present the alertView. But within the same method you are trying to present another view controller.
This will in turn call viewWillDisappear: where you are hiding the alertView.
It's recommended that if you want to present the alertView while displaying ViewController, create and display UIAlertView instance in the ViewController class's viewDidLoad or viewWillAppear:. Do not initialise and display it in this viewController.
To make the UIAlertView appear, you should call:
[contentLoadingController show];
Note that UIAlertView is deprecated in iOS9, and you should use UIAlertController.
I'm having troubles with my UIActionSheet on iPad view. I really have no idea why I can press any button available on the current view when it is active.
Example: BarButtonItem pressed. UIActionSheet appears like a popover, while it is showing you can press Back BarButtonItem.
Is there any way to avoid this? I've tried this on iPhone view and it's pretty fine.
Try like this.
First create a property
#property (weak, nonatomic) UIActionSheet *actionSheet;
#synthesize actionSheet = _actionSheet;
After that button action
- (IBAction)clickActionSheet:(UIBarButtonItem *)sender {
if (self.actionSheet) {
// do nothing
} else {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Action sheet demo" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Do something else" otherButtonTitles:DO_SOMETHING_ELSE, nil];
[actionSheet showFromBarButtonItem:sender animated:YES];
}
}
Implement this UIActionSheetDelegate
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex(NSInteger)buttonIndex
{
NSString *choice = [actionSheet buttonTitleAtIndex:buttonIndex];
if (buttonIndex == [actionSheet destructiveButtonIndex]) {
// destroy something
NSLog(#"Destroy");
} else if ([choice isEqualToString:DO_SOMETHING_ELSE]){
// do something else
NSLog(#"Do something else");
}
}
I'm currently writing an iOS app wherein I want to let the user pick an image from their photo library. I don't want them to be able to take a new photo or edit the existing one, but that's unimportant right now. Since this is an iPad app, I have to show the UIImagePickerController view in a popover view (or an exception is thrown, etc.). This is the code I am currently using to try to achieve that:
- (void)viewDidLoad{
[super viewDidLoad];
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){
_picker = [[UIImagePickerController alloc] initWithRootViewController:self];
_picker.delegate = self;
}else{
[[[UIAlertView alloc] initWithTitle:#"goto fail;" message:nil delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil] show];
}
self.view.backgroundColor = [UIColor purpleColor];
}
- (void)viewDidAppear:(BOOL)animated{
popoverController = [[UIPopoverController alloc] initWithContentViewController:_picker];
[popoverController presentPopoverFromRect:(CGRect){CGPointZero, {1, 1}} inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:animated];
[super viewDidAppear:animated];
}
I expect this to show an image picker view in a popover, obviously. Instead, I get this:
This code is running on a real iPad, not in the simulator. I have never been prompted to grant access to my photos, and there is no entry for the app in the photo area of the privacy settings of Preferences.app. I am testing this on an iPad 4 (which has a camera), and cannot test in the simulator, as it is having issues at the moment. I'm not really sure where the issue could be coming from - it's quite perplexing.
Also you should specify UIImagePicker's sourceType.
_picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
UPDATE
Initialise picker this way:
_picker = [[UIImagePickerController alloc] init];
I've been researching this and it seems that the only way to do this is using UIActionSheet, the question is that my UIActionSheet only covers half of the screen, my code is:
MyViewController *myVC = [[myViewController alloc] init];
UIActionSheet *myActionSheet = [[UIActionSheet alloc] initWithTitle:#"\n\n"
delegate:self
cancelButtonTitle:#"cancel"
destructiveButtonTitle:#"done"
otherButtonTitles:nil];
[myActionSheet addSubview:myVC.view];
[myActionSheet showInView:currentView];
[myActionSheet release];
Also how do I then dismiss this UIActionSheet from my MyViewController? Is there any better solution than this? Here's a screenshot of what I mean by loading half of the screen:
screenshot
Here's a sample project to illustrate my issue.
UIActionSheet will increase or decrease it's height according to the number of UIButtons in it. What you can do is add another view above your view with your desired alpha. And remove it from subview and add in subview according to your requirement i.e. add subview when you are displaying actionsheet and remove when you are dismissing UIActionSheet. I hope this is relevant to your question and it will help you to solve your problem.
The problem is because of the frame size of your TestViewController and method for adding the UIView as a subView of the UIActionSheet.
Make the following changes, and it is dismissing properly !
Implement willPresentActionSheet and addSubView in that method
- (IBAction)pressed:(id)sender
{
UIActionSheet *myActionSheet = [[UIActionSheet alloc] initWithTitle:#"\n\n" delegate:self cancelButtonTitle:#"cancel" destructiveButtonTitle:#"done" otherButtonTitles:nil];
[myActionSheet showInView:self.view];
[myActionSheet release];
}
- (void) willPresentActionSheet:(UIActionSheet *)actionSheet{
TestViewController *myVC = [[TestViewController alloc] init];
[actionSheet addSubview:myVC.view];
}
And in the viewDidLoad of the TestViewController, set
- (void)viewDidLoad
{
self.view.frame = CGRectMake(0,0 , 320, 60);
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
I have a method called -showMoreTools: which is: - (IBAction) showMoreTools:(id)sender {
UIActionSheet *popupQuery = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:#"Close" otherButtonTitles:#"Add Bookmark", #"Add to Home Screen", #"Print", #"Share", nil];
popupQuery.actionSheetStyle = UIActionSheetStyleDefault;
popupQuery.dismiss
[popupQuery showFromBarButtonItem:moreTools animated:YES];
[popupQuery release];
}
When an user taps a UIBarButtonItem it displays that UIActionSheet, but then, if the user wants to close the UIActionSheet without taping the Close button, (taping the UIBarButtonItem, then it displays the UIActionSheet over the first UIActionSheet.
It's possible to implement somehow taping another time the UIBarButtonItem to close the UIActionSheet?
Thank you so much – I'm a newbie in iOS Programming!
In order to dismiss it when you click on the button twice, you need to keep track of the currently displaying ActionSheet. We do this in our iPad app and it works great.
In your class that has the showMoreTools, in the header put:
#interface YourClassHere : NSObject <UIActionSheetDelegate> {
UIActionSheet* actionSheet_; // add this line
}
In the class file, change it to:
-(IBAction) showMoreTools:(id)sender {
// currently displaying actionsheet?
if (actionSheet_) {
[actionSheet_ dismissWithClickedButtonIndex:-1 animated:YES];
actionSheet_ = nil;
return;
}
actionSheet_ = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:#"Close" otherButtonTitles:#"Add Bookmark", #"Add to Home Screen", #"Print", #"Share", nil];
actionSheet_.actionSheetStyle = UIActionSheetStyleDefault;
[popupQuery showFromBarButtonItem:moreTools animated:YES];
[actionSheet_ release]; // yes, release it. we don't retain it and don't need to
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
// just set to nil
actionSheet_ = nil;
}
I found another solution to this. The problem is that when using showFromBarButtonItem, the toolbar view is automatically added to the popover's list of passthrough views. You can modify (and clear) the passthrough views when using a UIPopoverController directly, but not when it's presented as part of a UIActionSheet.
Anyway, by using showFromRect, there is no toolbar that the popover can automatically add to its passthrough views. So if you know the (approximate) rectangle where your button bar is, you can use something like:
CGRect buttonRect = CGRectIntersection(toolbar.frame, CGRectMake(0, 0, 60, self.frame.size.height));
[popupQuery showFromRect:buttonRect inView:self animated:YES];
In the above example, my button is on the left hand side of the toolbar.
try by setting the flag(YES/NO)
-(void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
use
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
My method is similar to christophercotton's.
In my showActionSheet I check if the actionsheet is visible rather than instantiated:
- (IBAction)showActionSheet:(id)sender
{
if ([self.fullActionSheet isVisible]) {
[self.fullActionSheet dismissWithClickedButtonIndex:-1 animated:NO];
_fullActionSheet = nil;
return;
}
//actionsheet code
}