UIImagePickerController overlayView and showsCameraControls issue - iphone

I'm trying to use a custom overlay on the UIImagePickerController and also be able to move and scale the resulting image. The problem is when I set showsCameraControls=YES, the overlay won't show but I can use the the move and scale functionality. However, when showsCameraControls=NO, the overlay appears, but when I take the picture, I don't even get the option to crop the image. The actual view loaded from the xib is just a UIToolbar with two buttons, one of which takes the picture
I have a controller (OverlayViewController) which loads the overlay from a xib file as it's view. This controller also has a UIImagePickerController so it sets the overlay of the UIImagePickerController to the view of the OverlayController. This first method is called in a different controller to set it all up and display it. In summary, I need to be able see the overlayView and use it's button to take the picture, which I can then move and scale
-(void) openCameraForImage
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
self.overlayViewController =
[[OverlayViewController alloc] initWithNibName:#"OverlayViewController" bundle:nil];
// as a delegate we will be notified when pictures are taken and when to dismiss the image picker
self.overlayViewController.delegate = self;
[self.overlayViewController setupImagePicker:UIImagePickerControllerSourceTypeCamera];
[self presentModalViewController:self.overlayViewController.imagePickerController animated:YES];
}
else {
[Common ShowAlert:#"Alert" andMessage:#"There is no camera on this device"];
}
}
This method is in OverlayViewController and does the work of setting up the Overlay.
- (void)setupImagePicker:(UIImagePickerControllerSourceType)sourceType
{
self.imagePickerController.sourceType = sourceType;
[self.imagePickerController setAllowsEditing:YES];
if (sourceType == UIImagePickerControllerSourceTypeCamera)
{
// user wants to use the camera interface
//
self.imagePickerController.showsCameraControls = NO; //This line allows overlay to show but move and scale doesn't work
self.imagePickerController.allowsEditing = YES;
//[self.view setUserInteractionEnabled:NO];
if ([[self.imagePickerController.cameraOverlayView subviews] count] == 0)
{
// setup our custom overlay view for the camera
//
// ensure that our custom view's frame fits within the parent frame
CGRect overlayViewFrame = self.imagePickerController.cameraOverlayView.frame;
CGRect newFrame = CGRectMake(0.0,
CGRectGetHeight(overlayViewFrame) -
self.view.frame.size.height - 10.0,
CGRectGetWidth(overlayViewFrame),
self.view.frame.size.height + 10.0);
self.view.frame = newFrame;
self.imagePickerController.cameraOverlayView = self.view;
}
}
}
This method in OverlayViewConroller takes the picture
- (IBAction)takePhoto:(id)sender
{
[self.imagePickerController takePicture];
}

I think you can put your image picker code in openCameraForImage
In your OverlayViewController, just use it to purely show the Overlay for your camera.
#implementation RiskCameraOverlayViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view setBackgroundColor:[UIColor blackColor]];
opUpImage = [UIImage imageNamed:#"camera_overlay_op_up"];
opDownImage = [UIImage imageNamed:#"camera_overlay_op_down"];
opUpFrameBegin = CGRectMake(0, -50, 320, 358);
opUpImageView = [[UIImageView alloc] initWithFrame:opUpFrameBegin];
[opUpImageView setImage:opUpImage];
opDownFrameBegin = CGRectMake(0, 265, 320, 314);
opDownImageView = [[UIImageView alloc] initWithFrame:opDownFrameBegin];
[opDownImageView setImage:opDownImage];
[self.view addSubview:opUpImageView];
[self.view addSubview:opDownImageView];
}
You might reach an issue where "Use photo" or "Retake" is not working, do a
[self.view removeFromSuperview];

Related

UIScrollView - Prevent UIImageView as subview of UIScrollView from being dragged off screen

I have a UIImageView element as a subview of my main UIScrollView element.
I want the Image to fill out the whole screen at all times, but I can drag the edges a bit too far, so that the yellow "background" becomes visible.
If I lift my finger, the Image "bounces" back and fills out the screen correctly.
I want to prevent this dragging of the image off screen.
I do however want the image to bounce back once I drag it out of the "safety area".
This is my ScrollView initialization:
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:CGRectMake(0, 0, frame.size.height, frame.size.width)];
if (self) {
[self initImageValues];
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
self.bouncesZoom = YES;
self.decelerationRate = UIScrollViewDecelerationRateFast;
self.delegate = self;
self.backgroundColor = [UIColor yellowColor];
self.minimumZoomScale = 1.0;
self.maximumZoomScale = 2.0;
[self setCanCancelContentTouches:YES];
self.clipsToBounds = YES;
// Load Image
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
[self addSubview:imageView];
[self setContentSize: CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
// Set bigger "bounce" zone (safety area)
self.contentInset=UIEdgeInsetsMake(-SAFETY_ZONE,-SAFETY_ZONE,-SAFETY_ZONE,-SAFETY_ZONE);
self.scrollEnabled = YES;
}
return self;}
Use these delegate methods:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
Then read the offset and return if it's out of the "safety area".
Could be that you need another delegate method from the UIScrollView though, but a workaround like this should fix your problem :)
try setting bounces on the scrollview:
self.bounces = NO;
TRY this:
**
self.scrollView.maximumZoomScale = 1.0;
self.scrollView.minimumZoomScale = 1.0;
**
Try setting its bounces property to NO.

Adding activityindicator on Default image - code given

I have an imaged name Default.png. This will load when the application is launching. Now i need to add an activity indicator to it. So it will spin and make the app look nice.
We know that we can't add any UI Components when the app is loading. So i thought to add the UIActivityIndicator in the didFinishLaunchingWithOptions method in the App delegate.
These are the steps i followed.
i added a view
added the default.png
added activity indicator
then
[window addSubView:view];
But nothing hapence.
Help how to write the code for this ?
You're on the right track, but you do need to add another UIView to your window (not another UIViewContoller, necessarily) temporarily. I do this sort of thing often. Here's some code that would be appropriate for your applicationDidFinishLaunching:withOptions: method:
[window makeKeyAndVisible]
...
// Create and show an overlay view with a spinner
UIImage *defaultImage = [UIImage imageNamed:#"Default.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:defaultImage];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
// Position the spinner appropriately for our splash image so it's not obscured
CGRect frame = spinner.frame;
frame.origin.x = imageView.frame.size.width / 2 - frame.size.width / 2;
frame.origin.y = imageView.frame.size.height / 5 * 4 - frame.size.height / 2;
spinner.frame = frame;
[spinner startAnimating];
[spinner setHidesWhenStopped:YES];
startupView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
[startupView addSubview:imageView];
[imageView release];
[startupView addSubview:spinner];
[spinner release];
[window addSubview:startupView];
The ivar startupView belongs to the app delegate, and later in the startup sequence another method removes it gracefully by fading it from view:
UIActivityIndicatorView *spinner = [[startupView subviews] lastObject];
[spinner stopAnimating];
[UIView animateWithDuration:1.0
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^(void) {
startupView.alpha = 0.0;
} completion:^(BOOL finished) {
[startupView removeFromSuperview];
[startupView release];
}];
It's worth mentioning that splash screens like this are not the "recommended" startup screen in Apple's view. But they do not seem to reject apps that have them.
I think that you wanna do a "custom splash screen" isnt it?
You cannot add the activity indicator in this way!
You need add a view controller, and at this view controller do stuff that you need with activity indicator!

UIImage view animate from one image to the next

I want to smothly animate an image in an UIImageView to turn into the next one within one second like UIModalTransitionStyleCrossDissolve does.
Currently, I've got an UIImageView * called "imageView" and a function which is called "imageForState" which returns me a UIImage * for the correct image.
So what I want to do is to animate the image A smoothly into image B if there is one.
Currently, my function is like that:
- (UIImage *) imageForState{
NSLog(#"state: %d", [save state]);
switch ([save state]) {
case 0:
case 1:
return [UIImage imageNamed:#"Sakuya_Debug.PNG"];
case 2:
return [UIImage imageNamed:#"Sakuya_2_Debug.PNG"];
default:
return NULL;
//Never called
}
}
-(void) tap{
[imageView setAnimationImages:[NSArray arrayWithObjects:[imageView image], [self imageForState], nil]];
imageView.animationDuration = 2.0;
[imageView startAnimating];
save.state++;
}
My problem is, that 1.) the animation goes on forever (when I set imageView.animationRepeatCount to 1, I end up at the first image again) and b.) the animation is not smooth; just like I would have used "setImage";
What am I doing wrong?
I suggest doing it with two imageViews and an animation block. In the following example I assume two square images with a siza of 100px. If you add the two imageViews as subviews make sure that imageB is added after imageA so it covers it.
Init the imageViews:
UIImageView *imageA = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Sakuya_Debug.PNG"]];
UIImageView *imageB = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Sakuya_2_Debug.PNG"]];
// hide the second image
imageB.alpha = 0.0;
// put the image with the same size at same position
imageA.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
imageB.frame = imageA.frame;
Blend method:
- (void)crossDissolveImageAtoB
{
[UIView animateWithDuration:1.0
animations:^{
imageB.alpha = 1.0;
}
completion:^(BOOL finished){
// do something after the animation finished,
// maybe releasing imageA if it's not used anymore...
}];
}

How to resize a UIModalPresentationFormSheet?

I am trying to display a modal view controller as a UIPresentationFormSheet. The view appears, but I can't seem to resize it. My XIB has the proper height & width, but it seems to get overridden when I call it like this:
composeTweetController = [[ComposeTweet alloc] initWithNibName:#"ComposeTweet" bundle:nil];
composeTweetController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:composeTweetController animated:TRUE];
Any thoughts? I am using the iPhone SDK 3.2 beta 4
You are able to adjust the frame of a modal view after presenting it:
Tested in iOS 5.1 - 7.1
MyModalViewController *targetController = [[[MyModalViewController alloc] init] autorelease];
targetController.modalPresentationStyle = UIModalPresentationFormSheet;
targetController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; //transition shouldn't matter
[self presentViewController:targetController animated:YES completion:nil];
if(floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1){
targetController.view.superview.frame = CGRectInset(targetController.view.superview.frame, 100, 50);
}else{
targetController.view.frame = CGRectInset(targetController.view.frame, 100, 50);
targetController.view.superview.backgroundColor = [UIColor clearColor];
}
Here's a method that works on iOS7 as well as iOS5 and iOS6: (arc)
-(void)presentController:(UIViewController*)controller fromRootController:(UIViewController*)rootController withSize:(CGSize)size
{
UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:controller];
nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
nav.modalPresentationStyle = UIModalPresentationFormSheet;
[rootController presentModalViewController:nav animated:YES];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
nav.view.superview.backgroundColor = [UIColor clearColor];
nav.view.bounds = CGRectMake(0, 0, size.width, size.height);
}
else
{
nav.view.superview.bounds = CGRectMake(0, 0, size.width, size.height);
}
}
composeTweetController = [[ComposeTweet alloc] initWithNibName:#"ComposeTweet" bundle:nil];
composeTweetController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:composeTweetController animated:TRUE];
//if you want to change its size but the view will remain centerd on the screen in both portrait and landscape then:
composeTweetViewController.view.superview.bounds = CGRectMake(0, 0, 320, 480);
//or if you want to change it's position also, then:
composeTweetViewController.view.superview.frame = CGRectMake(0, 0, 320, 480);
As of iOS7 you can simply do
composeTweetController.preferredContentSize = CGSizeMake(380.0, 550.0);
Tested and works for iOS 6, using XCode 4.5
I stumbled upon my answer after reading much of the tips on here:
In the viewWillAppear:(BOOL)animated method:
[super viewWillAppear:animated];
//resize modal view
self.view.superview.bounds = CGRectMake(0, 0, 432, 680);
In the viewDidAppear:(BOOL)animated method:
CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.width/2, [[UIScreen mainScreen] bounds].size.height/2);
self.view.superview.center = centerPoint;
I tried to add the centering code in the same place as the resizing code, but that did not work. For some reason, it only works after the view has appeared on the screen.
I surmise that it has something to do with the way that UIModalPresentationFormSheet works, because when I was stepping through in the LLDB debugger, I noticed that there was a variable _formSheetSize that was still {540, 620}. Go figure.
This will work with any UIModalTransitionStyle
#interface BaseDialog ()
#property(nonatomic,assign) CGRect origFrame;
#end
#implementation BaseDialog
-(void)viewDidLoad{
[super viewDidLoad];
self.origFrame=self.view.frame;
}
-(CGSize)formSheetSize{
return self.origFrame.size;
}
Following first code is how to present your model view controller
composeTweetController = [[ComposeTweet alloc] initWithNibName:#"ComposeTweet" bundle:nil];
composeTweetController.modalPresentationStyle = UIModalPresentationFormSheet;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:composeTweetController];
navigationController.delegate = self;
[self presentModalViewController:navigationController animated:YES];
And In your ComposeTweet controller class
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.view.superview.frame = CGRectMake(0, 0,500,400);
}
iOS 7
So the approach of setting the superview's frame or bounds doesn't work anymore on iOS 7 (for UIModalTransitionStyleCoverVertical). You can, however, now set the background color of the superview to clear and then change the frame of the modal view controller how you see fit.
So in iOS 7 you will want to:
present the view controller (presentation mode: UIModalPresentationFormSheet)
set view controller superview background color to clear
change frame of view controller as desired (perhaps making it smaller and then centering it in superview)
I got a full screen modal view from UIPresentationFormSheet with just this line:
modalViewController.view.superview.bounds = CGRectMake(0, 0, 1024, 748);
#bdrobert sadly your nice solution does not work anymore on iOS6 - the container keeps the original size even though the new viewcontroller is embedded with the custom size.
You probably need to use the containment API introduced in iOS5, but you need to add a dimmed background on your own, fetching all touch events for that area.
On change of orientation, this code work perfect....
settingViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:settingViewController animated:YES completion:nil];
settingViewController.view.superview.frame = CGRectMake(0, 0, 700, 700);
UIInterfaceOrientation currentOrientation = [self getDeviceOrientation];
if(currentOrientation == UIInterfaceOrientationPortrait || currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.width/2, [[UIScreen mainScreen] bounds].size.height/2);
settingViewController.view.superview.center = centerPoint;
}
else
{
CGPoint centerPoint = CGPointMake([[UIScreen mainScreen] bounds].size.height/2, [[UIScreen mainScreen] bounds].size.width/2);
settingViewController.view.superview.center = centerPoint;
}
The modern ios13 way:
use popover (formsheet and page ignore preferredContentSize)
then set or override preferredContentSize aka Ed Pilowat & Co
The view size is fixed. You will have to implement things yourself if you want something different.

uiscrollview not switching image subviews

I'm building a comic viewer app, that consists of two view controllers, the root viewcontroller basically displays a view where a user decides what comic they want to read by pressing a button. The second viewController actually displays the comic as a uiscrollview with a toolbar and a title at the top.
So the problem I am having is that the comic image panels themselves are not changing from whatever the first comic you go to if you select another comic after viewing the first one. The way I set it up, and I admit it's not exactly mvc, so please don't hate, anyway the way I set it up is each comic uiscrollview consists of x number of jpg images where each comic set's image names have a common prefix and then a number like 'funny1.jpg', 'funny2.jpg', 'funny3.jpg' and 'soda1.jpg', 'soda2.jpg', 'soda3.jpg', etc...
so when a user selects a comic to view in the root controller it makes a call to the delegate and sets ivars on instances of the comicviewcontroller that belongs to the delegate (mainDelegate.comicViewController.property) I set the number of panels in that comic, the comic name for the title label, and the image prefix.
The number of images changes(or at least the number that you can scroll through), and the title changes but for some reason the images are the same ones as whatever comic you clicked on initially.
I'm basing this whole app off of the 'scrolling' code sample from apple.
I thought if I added a viewWillAppear:(BOOL) animated call to the comicViewController everytime the user clicked the button that would fix it but it didn't, after all that is where the scrollview is laid out.
Anyway here is some code from each of the two controllers:
RootController:
-(IBAction) launchComic2{
AppDelegate *mainDelegate = [(AppDelegate *) [UIApplication sharedApplication] delegate];
mainDelegate.myViewController.comicPageCount = 3;
mainDelegate.myViewController.comicTitle.text = #"\"Death by ETOH\"";
mainDelegate.myViewController.comicImagePrefix = #"etoh";
[mainDelegate.myViewController viewWillAppear:YES];
[mainDelegate.window addSubview: mainDelegate.myViewController.view];
comicViewController:
-(void) viewWillAppear:(BOOL)animated {
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor whiteColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= self.comicPageCount; i++)
{
NSString *imageName = [NSString stringWithFormat:#"%#%d.jpg", self.comicImagePrefix, i];
NSLog(#"%#%d.jpg", self.comicImagePrefix, i);
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((self.comicPageCount * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
Any help would be appreciated on this.
Nick
So what I ended up doing is just making multiple instances of the comic controller inside the delegate instead of just re-using the one. Will update this if I run into problems.
Nick