dismissModalViewController not working as expected - iphone

I have a problem that I'm helping someone can shed some light on. I'm sure it is something very simple, but I just can't see it and could really use an extra set of eyes to help find this bug.
The app I'm working on uses UIImagePickerController to present a camera preview with the stock camera UI hidden. This preview implements a cameraOverlay view with a few buttons to perform my required tasks, one of which is to dismiss the camera preview.
For some reason, the function to dismiss the camera view will not work when being called by the button in the overlay view. I can NSLog the function and see that it is in fact being called by the button, but simply doesn't allow the dismissModalViewController to work. I have tested the function by having an NSTimer call it a few seconds after it loads, and it works fine, just not when I call it from the button in the cameraOverlay.
My viewController (CameraTestViewController.m) calls the UIImagePicker as shown below with the press of a button.
-(IBAction) getPhoto:(id) sender {
OverlayView *overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGTH)];
picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
picker.cameraOverlayView = overlay;
picker.showsCameraControls = NO;
picker.toolbarHidden = YES;
[self presentModalViewController:picker animated:NO];
//[self performSelector:#selector(doCancel) withObject:nil afterDelay:10];
}
I dismiss the camera view with this method elsewhere in the viewController
-(void)doCancel
{
NSLog (#"doCancel method has been called");
[picker dismissModalViewControllerAnimated:YES];
}
Then in my OverlayView.m class, I set up the required buttons and provide a method that calls the dismissing of the modal view controller.
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Clear the background of the overlay:
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
...
myButton04 = [UIButton buttonWithType:UIButtonTypeCustom];
myButton04.frame = CGRectMake(10, 447, 44, 13);
[myButton04 setTitle:#"" forState:UIControlStateNormal];
[myButton04 addTarget:self action:#selector(scanButton05TouchUpInside) forControlEvents:UIControlEventTouchUpInside];
[myButton04 setImage:[UIImage imageNamed:#"camControlsBack.png"] forState:UIControlStateNormal];
[self addSubview:myButton04];
...
}
return self;
}
- (void) scanButton05TouchUpInside {
NSLog(#"BACK BUTTON HAS BEEN PRESSED");
CameraTestViewController *baseViewController = [[CameraTestViewController alloc] init];
[baseViewController doCancel];
}
ANY help on this would be most appreciated. I'm sick of having a purple forehead from beating my head against the wall over this one. :cool:
THANKS!

Use this Below code:
[[[self presentingViewController] presentingViewController] dismissModalViewControllerAnimated:YES];

The way I dismiss my modalViewController is to call its parent:
[[picker parentViewController] dismissModalViewControllerAnimated:YES];

Related

UIButton Image not changing/updating

First off I am still new to objective-c and still trying to learn as much as I can so please bear with me.
Right now I have a UIButton that I've created programmatically. When the button is pressed an UIActionSheet is brought up with the choice of "Camera," "Choose Photo" or "Cancel." The button image is then suppose to change to the image taken (if camera was chosen) or image picked (if the camera roll was chosen).
My problem is the button's image is not changing after UIImagePicker is dismissed. At first the button was created as a subView of a tableView and when I scrolled the tableView, it refreshed the button and the image changed (this is not how I wanted it to behave of course). However if the user decides they want to change or remove the image, they just push the button again and the UIActionSheet displays a third choice to "Remove Photo." After scrolling the tableView I realized the button image was not changing at all, but instead a new button was created on top of the old button so I move the UIButton code to viewDidLoad instead (based upon some information found here on stackoverflow). I have also removed the ability for the tableView to scroll as I did not need scrolling for it.
I've been trying to solve this problem for a few days now how to refresh either the button, or the view properly after either UIImagePicker is dismissed or UIActionSheet is dismissed. I have tried using setNeedsLayout and setNeedsDisplay but these have not worked to fix my problem (I might be putting these in the wrong place). Hopefully someone has insight on this and can guide me on the proper way to make this work. Also provided is my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// Creates camera button and connects to camera menu UIActionSheet
UIButton *cameraButton = [UIButton buttonWithType:UIButtonTypeCustom];
[cameraButton addTarget:self action:#selector(showActionSheet:) forControlEvents:UIControlEventTouchUpInside];
cameraButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
cameraButton.titleLabel.textAlignment = UITextAlignmentCenter;
cameraButton.frame = CGRectMake(9, 230, 80, 80);
[self.view addSubview:cameraButton];
picturePresent = NO;
NSLog(#"picturePresent = %#", picturePresent);
}
-(void)showActionSheet:(id)sender {
if (picturePresent == NO) {
UIActionSheet *cameraMenuSheet = [[UIActionSheet alloc] initWithTitle:#"Add Photo"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Camera", #"Choose Photo", nil];
[cameraMenuSheet showFromTabBar:self.tabBarController.tabBar];
}
else if (picturePresent == YES) {
UIActionSheet *cameraMenuSheet = [[UIActionSheet alloc] initWithTitle:#"Add Photo"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Remove Photo", #"Camera", #"Choose Photo", nil];
[cameraMenuSheet showFromTabBar:self.tabBarController.tabBar];
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *title = [actionSheet buttonTitleAtIndex:buttonIndex];
// Initialize UIImagePickerController
if ([title isEqualToString:#"Camera"]) {
// Camera
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
imagePicker.allowsEditing = NO;
imagePicker.showsCameraControls = YES;
imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, nil];
[self presentModalViewController:imagePicker animated:YES];
newMedia = YES;
}
else if ([title isEqualToString:#"Choose Photo"]) {
// Photo library
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePicker.delegate = self;
imagePicker.allowsEditing = NO;
imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, nil];
[self presentModalViewController:imagePicker animated:YES];
newMedia = NO;
}
else if ([title isEqualToString:#"Remove Photo"]) {
picturePresent = NO;
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
[self.view setNeedsDisplay];
}
// Method for saving image to photo album
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
UIImage *scaledImage = [image scaleToSize:CGSizeMake(80.0, 80.0)];
if (newMedia == YES) {
// Save image
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
}
resizedImage = scaledImage;
}
picturePresent = YES;
[self dismissModalViewControllerAnimated:NO];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self dismissModalViewControllerAnimated:YES];
}
Additionally, now that I have moved my UIButton coding to viewDidLoad I am unsure of where to put this piece of coding:
{
if (picturePresent == NO) {
[cameraButton setTitle:#"Add\nPhoto" forState:UIControlStateNormal];
}
else if (picturePresent == YES) {
[cameraButton setImage:resizedImage forState:UIControlStateNormal];
}
}
Also setImage and setBackgroundImage were both used and still not working how I want it to. Let me know if more information is needed, thanks!
EDIT:
Here are some screenshots to show what I am aiming for -
"Picture" is suppose to represent a picture that was taken or selected and then scaled to fit the button size.
Did not test it, but if you make your cameraButton member of your UiViewController so that you can access whenever needed, you could call the setImage: forState: right after caculating the resizedImage - no picturePresent bool needed. And I think setNeedsDisplay Not needed as well.
EDIT:
In your view controller header file do something like
...
#interface MyViewController : UIViewController
{
...
UIButton * cameraButton;
...
}
...
Somewhere in your implementation file (viewDidiLoad is Ok) do:
...
cameraButton = [UIButton buttonWithType:UIButtonTypeCustom];
...
[self.view addSubview:cameraButton];
...
And then implement all the other stuff you did and change the code in didFinishPickingMediaWithInfo like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
...
[cameraButton scaledImage forState:UIControlStateNormal];
}
As I said, didn't test it, but I think it should work.
Move the viewDidLoad code to the end of imagePickerController:didFinishPickingMediaWithInfo:. Also if you can post a few screenshots it will help explain exactly what is going on, as well as what you expect. This could be a cropping issue, which is why I suggest posting screenshots.
long time i've searched for answers..now here some:
to change image of a button the code below helped me:
[button.imageView setHighlighted:YES];
[button.imageView setHighlightedImage:[UIImage imageNamed:#"mypic.png"]];
[button.imageView setImage:[UIImage imageNamed:#"mypic.png"]];
..e.g. in viewDidLoad.
hope that helps...

presenting modal on top of MPMoviePlayerController leads to crash, but only in iOS < 5.0

So, here's the situation (this is all in the simulator):
create a view controller. it owns an MPMoviePlayerController, and adds the player's view as a subview to its own.
set this vc as the window's rootViewController.
also in this vc's view is a button which will launch a modal view controller (which obscures the movie) after pausing the movie player.
click the button, launch the modal VC, then dismiss it.
notice that the paused image of the movie player is gone (it is just black).
click "play" to resume playing the movie
crash
Now, change your build target from iOS 4.3 to iOS 5.0 and it works flawlessly.
What's really bothering me is that this didn't cause a crash under 4.3 a month ago. In fact, I have an app in the store right now for which this works just fine: http://itunes.apple.com/us/app/es-musica-free/id474811522?mt=8
So, I've tried to boil this down to a minimal example which reproduces the problem.
Create a vanilla xcode project.
in your AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.backgroundColor = [UIColor blackColor];
[self.window makeKeyAndVisible];
UIViewController *vc = [[DemoMoviePlayerViewController alloc] init];
[self.window setRootViewController:vc];
[vc release];
vc = nil;
return YES;
}
DemoMoviePlayerViewController is pretty simple. here's the h file:
#import
#import
#interface DemoMoviePlayerViewController : UIViewController
{
MPMoviePlayerController *moviePlayer_;
}
#end
and the m file:
#import "DemoMoviePlayerViewController.h"
#interface DemoMoviePlayerViewController (InternalMethods)
- (void)_buttonPressed:(UIButton*)button;
#end
#implementation DemoMoviePlayerViewController
- (id)init
{
self = [super init];
if (self == nil)
{
return nil;
}
[self setWantsFullScreenLayout:YES];
NSURL *url = [NSURL URLWithString:#"http://once.unicornmedia.com/now/od/auto/0116d5af-bdc1-456d-a3ac-e3cbe25bac98/c762a821-e583-420c-b798-7b8c66736027/6c0e77e0-6dc4-48d5-9197-26e59271e8dd/content.once"];
moviePlayer_ = [[MPMoviePlayerController alloc] initWithContentURL:url];
return self;
}
- (void)dealloc
{
[moviePlayer_ stop];
[moviePlayer_ release];
moviePlayer_ = nil;
[super dealloc];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor redColor]]; // debug
[[moviePlayer_ view] setFrame:[[self view] bounds]];
[[moviePlayer_ view] setAutoresizingMask:(UIViewAutoresizingFlexibleWidth
|UIViewAutoresizingFlexibleHeight)];
[moviePlayer_ setControlStyle:MPMovieControlStyleFullscreen];
[[moviePlayer_ view] setBackgroundColor:[UIColor greenColor]]; // debug
[[self view] addSubview:[moviePlayer_ view]];
// add a button to launch share kit
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"launch modal" forState:UIControlStateNormal];
[button addTarget:self
action:#selector(_buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[[moviePlayer_ view] addSubview:button];
[button setFrame:CGRectMake(20, 100, 200, 40)];
[moviePlayer_ setShouldAutoplay:YES];
[moviePlayer_ play];
}
#pragma mark - internal methods -
- (void)_dismissModal
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)_buttonPressed:(UIButton*)button
{
if ([moviePlayer_ currentPlaybackRate] == 1.0)
{
[moviePlayer_ setShouldAutoplay:NO];
[moviePlayer_ pause];
}
[self performSelector:#selector(_dismissModal) withObject:nil afterDelay:3.0];
UIViewController *vc = [[UIViewController alloc] init];
[[vc view] setBackgroundColor:[UIColor blueColor]];
[self presentModalViewController:vc animated:YES];
// yeah I know, vc is leaked...
}
#end
So apparently, somehow the MPMoviePlayerController is somehow able to detect which its view gets obscured, despite the fact that my view controller isn't doing anything fancy in viewWillDisappear or viewDidDisappear.
Again, what really bothers me is that, to the best of my knowledge, this worked just fine under 4.3 about a month ago.

UIImageView tap to hide navigation bar

I have a view which shows an image from the web. The view only has an UIImageView. I want to know how to hide the navigationBar when the user taps and show it again when the user re-taps the view again. (Just like the native iPhone photo app)
I know i can use this
[self.navigationController setNavigationBarHidden:YES animated:YES];
but i am not sure where to use this,where to put in this code.
Help would be appreciated
Initialize a new UITapGestureRecognizer:
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(toggleNavigationBar:)];
tapGestureRecognizer.numberOfTapsRequired = 1;
tapGestureRecognizer.numberOfTouchesRequired = 1;
[self.imageView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];
You also must make sure the UIImageView has userInteractionEnabled set to YES because by default it is set to NO on UIImageView's.
self.imageView.userInteractionEnabled = YES;
Finally, write the method that is called when the gesture recognizer recognizes. This is the method selector that is passed in the action: argument in the gesture recognizer's initializer method:
- (void)toggleNavigationBar:(UITapGestureRecognizer *)tapGestureRecognizer
{
[self.navigationController setNavigationBarHidden:![self.navigationController isNavigationBarHidden] animated:YES];
}
Put a UITapGestureRecognizer on your UIImageView and in the delegate just call the method you mentioned. Something like this:
UITapGestureRecognizer* g = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTapped:)];
[img addGestureRecognizer:g];
[g release];
Then your delegate:
-(void) imageTapped:(UITapGestureRecognizer*)tg
{
if(self.navigationController.toolbarHidden)
[self.navigationController setNavigationBarHidden:YES animated:YES];
else
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
If you can't figure out the other answers you can cheat a little bit. You can throw on a button set it to transparent and link a IBAction to it with the code:
UIButton *imageButton = [[UIButton alloc] initWithFrame:CGRectMake( x,y,0,0)];
imageButton.backgroundColor = [UIColor clearColor];
[imageButton addTarget:self action:#selector(navBarHide:)
forControlEvents:UIControlEventTouchUpInside];
-(IBAction)navBarHide {
if (!navBarHidden) {
[self.navigationController.navigationBar removeFromSuperView];
}
else {
[YourUIView addSubview: yourNavigationBar];
}
}

How to add image overlay to UIImagePickerControllerSourceTypePhotoLibrary when editing?

I've tried looking everywhere for an answer to this but can not find any useful info.
Basically, I want the user to pick a picture from the album, and then have the app display the picture in the edit/crop mode.
On this edit screen I want to display an overlay screen for the user to use to align his image.
He then clicks the save button which saves the edited picture with the overlay image by just merging the images.
The only thing I can not find how to do is add the overlay image in the edit screen!
I can do this quite easily when:
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
But when:
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
I can not use:
imagePicker.cameraOverlayView = overlayGraphicView;
and that is my issue.
Also if I add an UIimage as a subview instead then this overlay, it stays on the screen even when the user is choosing his image from the album. I only want the overlay to appear after the image has been chosen for editing and before it has been saved to the album after the editing has finished.
Thanks for your help.
Heres the method:
- (IBAction)pickPhotoButton:(id)sender {
NSLog(#"Pick a Current Photo Button Pressed...");
// Create image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// Delegate is self
imagePicker.delegate = self;
// Allow editing of image ?
imagePicker.allowsEditing = YES;
// Show image picker
[self presentModalViewController:imagePicker animated:YES];
}
and heres my save to album method:
// Save the image to photo album
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerEditedImage"];
// Combine image with overlay before saving!!
image = [self addOverlayToImage:image];
// Save image
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
[picker release];
}
You can become UIImagePickerController object's delegate and keenly observe the UINavigationControllerDelegate methods - navigationController:didShowViewController:animated: and navigationController:willShowViewController:animated:. You can know when the second view controller is coming on and later add your overlay to the view controller's view. Sample usage is shown below –
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ( [navigationController.viewControllers count] == 2 ) {
overlayView.center = CGPointMake(135, 135);
overlayView.bounds = CGRectZero;
[viewController.view addSubview:overlayView];
[UIView beginAnimations:#"animateTableView" context:nil];
[UIView setAnimationDuration:0.4];
[overlayView setFrame:CGRectMake( 50, 50, 220, 220)];
[UIView commitAnimations];
}
}
You can use the following customised method for adding overlays to the Imagepickercontroller
In yourclassname .h file define
#property (nonatomic, retain) UIImagePickerController* m_Pickercontroller;
#property(nonatomic,retain) UIView *cameraOverlayView;
In yourclassname.m file
-(void)Loadcaptureview
{
//Allocating Image Picker Controller
m_Pickercontroller=[[UIImagePickerController alloc] init ];
m_Pickercontroller.delegate=self;
m_Pickercontroller.allowsEditing=YES;
m_Pickercontroller.sourceType=UIImagePickerControllerSourceTypeCamera;
m_Pickercontroller.view.frame=CGRectMake(0, 0, 320, 300);
UIButton*Clickbutton=[[UIButton alloc] initWithFrame:CGRectMake(50,200, 60, 60)];
[Clickbutton setImage:[UIImage imageNamed:#"red-circle-button.png"] forState:UIControlStateNormal];
[Clickbutton addTarget:self action:#selector(clicked:) forControlEvents:UIControlEventTouchUpInside];
image1=[[UIImageView alloc] initWithFrame:CGRectMake(50,400, 60, 60)];
image1.image=[UIImage imageNamed:#"red-circle-button.png"];
[m_Pickercontroller.cameraOverlayView addSubview:Clickbutton];
[m_Pickercontroller.cameraOverlayView addSubview:image1];
[m_Pickercontroller.cameraOverlayView bringSubviewToFront:image1];
//Hiding the Camera Control
m_Pickercontroller.showsCameraControls=NO;
//Presenting the imagepicker Controller to Present Modal view Controller
[self.navigationController presentModalViewController:m_Pickercontroller animated:YES];
}
// Calling the Function
- (void)viewDidLoad
{
[self Loadcaptureview];
}

Re-using the UIImagePickerController.cameraOverlayView

I have a hierarchy of views:
compView with two children:
bgView
objectView.
I'm passing objectView to the cameraOverlayView property of the UIImagePickerController. Once the ImagePicker is done I update the image in the bgView and I would like to continue to display the view tree including the objectView which was passed to the UIImagePickerController as an overlayView.
The problem is that after calling dismissModalViewControllerAnimated to close the UIImagePickerController, the objectView is not appearing, as if the UIImagePickerContoller is hiding it. I checked in the debugger and it doesn't seem to be dealocated. The pointer is still valid. But the view is not showing.
Any ideas of what I might be doing wrong?
Thanks,
Eddy
Here a bit of code to show you what I'm doing:
From myViewController.m:
- (void)loadView {
CGRect rect = self.navigationController.view.bounds;
compView = [[UIView alloc] initWithFrame:rect];
bgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Storage/dummy_bg.png"]];
objectView = [[PropImageView alloc] initWithImage:[UIImage imageNamed:#"Storage/rasta.png"]];
[objectView setUserInteractionEnabled:YES];
[objectView setMultipleTouchEnabled:YES];
[compView addSubview:bgView];
[compView addSubview:objectView];
self.view = compView;
[self placeObject];
[objectView release];
[bgView release];
[compView release];
}
- (void) placeObject
{
NSLog(#"camera button pressed");
// make sure camera is avaialble before setting it as source
//
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
#if !TARGET_IPHONE_SIMULATOR
UIImagePickerController* picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
picker.allowsEditing = NO;
picker.view.hidden = NO;
picker.cameraOverlayView = objectView;
[self presentModalViewController:picker animated:NO];
[picker release];
#endif
}
// from PickImageAppDelegate.m
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
// Dismiss the image selection, hide the picker and
[picker dismissModalViewControllerAnimated:YES];
bgView.image = [self rotateImage:image byOrientationFlag:UIImageOrientationRight];
}
[picker dismissModalViewControllerAnimated:YES];
That should be
[self dismissModalViewControllerAnimated:YES];