Popover presentation on an iPhone using UIPopoverPresentationController - ios

Hello everyone I want to make a popover for iPhone so here is my code where I am geting wrong please suggest I want to create somthing like below pic but mine is covering the whole screen and I dont want to use segue .So basicaly I want if I click on button a resized View controller should popup how can I achieve this please help.I had followed this tutorial.
https://www.youtube.com/watch?v=UQBbJQNEDA4
#import "ViewController.h"
#import "Popup.h"
#interface ViewController ()<UIPopoverPresentationControllerDelegate>
{
Popup * popupController;
UIPopoverPresentationController *popupPresentationController;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)popupOnClick:(id)sender {
popupController=[self.storyboard instantiateViewControllerWithIdentifier:#"Popup"];
popupController.modalPresentationStyle=UIModalPresentationPopover;
popupPresentationController= [popupController popoverPresentationController];
popupPresentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
popupController.preferredContentSize=CGSizeMake(150, 300);
popupPresentationController.delegate = self;
[self presentViewController:popupController animated:YES completion:NULL];
// in case we don't have a bar button as reference
popupPresentationController.sourceView = _popupButton;
popupPresentationController.sourceRect = _popupButton.frame;
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection {
return UIModalPresentationNone;
}
#end

Here's your problem:
[self presentViewController:popupController animated:YES completion:nil];
popupPresentationController= [popupController popoverPresentationController];
popupPresentationController.delegate = self;
That code is in the wrong order. You must set the delegate before calling presentViewController.

Related

Objective C MFMailComposeViewController Cancel -> Cancel button not working

Please find the code and attached pic. That cancel button not working . If I click that button, that modal alone closing. It is not triggering "mailComposeController:didFinishWithResult" function..I am new to Objective c IOS. Please help me to get out of this issue. I searched in stack overflow. But I problem didn't solve
#import "ViewController.h"
#import <MessageUI/MFMailComposeViewController.h>
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *send;
- (IBAction)sendMail:(id)sender;
#end
#implementation ViewController
MFMailComposeViewController* controller;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
controller= [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sendMail:(id)sender {
[controller setSubject:#"My Subject"];
[controller setMessageBody:#"Hello there." isHTML:NO];
if (controller) [self presentViewController:controller animated:YES completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error;
{
NSLog(#"Coming here");
if (result == MFMailComposeResultSent) {
NSLog(#"Mail It's away!");
}
if (result == MFMailComposeResultFailed) {
NSLog(#"Mail Error!");
}
if(result == MFMailComposeResultCancelled){
NSLog(#"Mail Error!");
}
if(result == MFMailComposeResultSaved){
NSLog(#"Mail Saved!");
}
[controller dismissViewControllerAnimated:YES completion:nil];
return;
}
[![Screen shot][1]][1]#end
Man this cancel button does nothing at all other than dismissing action sheet. If you want to get rid of mail composer you have to press cancel at upper left corner which shows you an action sheet at the bottom with options Delete Draft, Save Draft and cancel. Delete draft and save draft will dismiss the mail composer and the delegate function will be called. Cancel button will actually dismiss action sheet in order to save the mail composer from dismissing in case if user accidentally clicked that cancel button at the top

iOS app crashes without any exception after tapping IBOutlet with assigned IBAction (UIButton)

My task is to create custom UIAlertView with multiline text input field and everything works pretty much well up to the point where I need to do some actions if dismiss button was tapped. As example I'm using: http://iphonedevelopment.blogspot.co.uk/2010/05/custom-alert-views.html
I have created very simple popup for testing purpose. Basically it's UIViewController xib with single button in it. The main class is demonstrated below:
#import "testViewController.h"
#interface testViewController ()
#end
#implementation testViewController
- (id)init
{
self = [super initWithNibName:#"testViewController" bundle:nil];
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)showInView:(UIView *)view
{
[view addSubview:[self view]];
[[self view] setFrame: [view bounds]];
[[self view] setCenter:[view center]];
}
- (IBAction)onTap:(id)sender {
NSLog(#"All OK");
}
#end
then in root UIViewController I'm calling my custom alert:
- (IBAction)showAlert:(id)sender
{
dispatch_async(dispatch_get_main_queue(), ^{
testViewController *alert = [[testViewController alloc] init];
[alert showInView:[self view]];
});
}
So far I have tried Main thread or global queue or even synchronous dispatch, but everything ends up with break on:
int main(int argc, char * argv[]) {
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); <-- Thread 1:EXC_BAD_ACCESS (code=1, address=0xa000000c)
}
}
tried to add observer for the button but still no go..
Any help is much appreciated
Here what happing is "if you want to add one viewcontroller view to other viewcontroller's view then after adding of views you should convey to the compiler that second view controller is going to be child to the first"
i.e pre intimation of parent to child relationship has to be done.
now just modify your showAlert method with the following . it is working 100%.
- (IBAction)showAlert:(id)sender {
dispatch_async(dispatch_get_main_queue(), ^{
testViewController *alert = [[testViewController alloc] init];
[alert showInView:[self view]];
[self addChildViewController:alert];
[alert didMoveToParentViewController:self];
});
}
Check if your UIButton is assigned multiple IBoutlets or multiple IBActions. This a common issue which happens without our notice sometimes.
It turns out that my testViewController was released by ARC before I tap the button

Full Screen Custom Popover issue in iOS7 and iOS8

I am developing an app for iPad only. In which in for one functionality i want to display FullCustom Popover.
For that my code is as below:-
DuplicateViewController *viewControllerForPopover =
[self.storyboard instantiateViewControllerWithIdentifier:#"DuplicatePopoverVC"];
viewControllerForPopover.arr_studentDetail = self.arrStudentDetail;
viewControllerForPopover.dictSelectedProg = dictSelectedProgram;
self.popover = [[UIPopoverController alloc]
initWithContentViewController:viewControllerForPopover];
[self.popover setPopoverContentSize:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];
viewControllerForPopover.modalPresentationStyle = UIModalPresentationFullScreen;
[self.popover setBackgroundColor:[[UIColor darkGrayColor] colorWithAlphaComponent:0.4]];
[self.popover presentPopoverFromRect:self.view.bounds inView:self.view permittedArrowDirections:0 animated:YES];
I set popover size and tried with other option but can't make it full screen.
ViewDidLoad -> DuplicateViewController
[view_main.layer setBorderWidth:5.0f];
[view_main.layer setCornerRadius:25.0f];
[view_main.layer setBorderColor:[UIColor colorWithRed:(29.0f/255.0f) green:134.0f/255.0f blue:140.0f/255.0f alpha:1.0f].CGColor];
But while running App, It display as below:-
Please help me to display full screen Popover. Thank you so much in advance.
create two classes
the first one should inherit UIPopoverController
the second one should inherit UIPopoverBackgroundView
for example:
CustomUIPopoverController.h
#interface CustomUIPopoverController : UIPopoverController
CustomUIPopoverController.m
#implementation CustomUIPopoverController
- (id)initWithContentViewController:(UIViewController *)viewController {
self = [super initWithContentViewController:viewController];
if (self) {
self.popoverBackgroundViewClass = [CustomUIClearPopoverBackgroundView class];
[self setPopoverContentSize:viewController.view.frame.size];
}
return self;
}
#end
CustomUIClearPopoverBackgroundView.h
#interface CustomUIClearPopoverBackgroundView : UIPopoverBackgroundView
CustomUIClearPopoverBackgroundView.m
#import "CustomUIClearPopoverBackgroundView.h"
#implementation CustomUIClearPopoverBackgroundView
#pragma mark - no arrow
+ (CGFloat)arrowHeight {
return 0;
}
+ (CGFloat)arrowBase {
return 0;
}
- (CGFloat)arrowOffset {
return 0;
}
- (void)setArrowOffset:(CGFloat)arrowOffset {
}
- (UIPopoverArrowDirection)arrowDirection {
return 0;
}
- (void)setArrowDirection:(UIPopoverArrowDirection)arrowDirection {
}
#pragma mark - no margins
+ (UIEdgeInsets)contentViewInsets {
return UIEdgeInsetsZero;
}
#pragma mark - fully transparent (default is 0.15)
+(BOOL)wantsDefaultContentAppearance {
return NO;
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
// hide shadow image view
[self.superview.subviews[0] setHidden:YES];
}
#end
I used this but I don't like it very much.
the second option is to create a container view and hide/show it as you like.
this way it's a pure view controller and you don't need to mess with popup stuff
to create the transparency, make your container view background = clear, the view controller view background color = clear, and add a semi-transparent button in the size of the view controller for the semi-transparent black background. on click of the button close the window (= same effect as tapping the popup background)

Display photos in different UIImageViews

In my test app, I have two buttons (takePhoto1 and takePhoto2) and two UIImageViews (photo1View and photo2View). The first button takes a photo and displays it in the first image view. The second button takes another photo, and is supposed to display it in the second image view. However, for some reason second photo is displayed in photoView1 instead of photoView2.
I haven't implemented any code to save the photos yet, so I'm not worried about the photos persisting in the image views.
What I do need to figure out is how to make sure when the second photo is taken, it is displayed in the appropriate view. Here is what I have so far:
//Take photo1 and display in top image view
- (void)takePhoto1;
{
[self dismissViewControllerAnimated:YES completion:NULL];
if ([self.capturedImages count] > 0)
{
if ([self.capturedImages count] == 1)
{
// Camera took a single picture.
[self.photo1View setImage:[self.capturedImages objectAtIndex:0]];
}
// To be ready to start again, clear the captured images array.
[self.capturedImages removeAllObjects];
}
self.imagePickerController = nil;
}
//Take photo2 and display in bottom image view
- (void)takePhoto2;
{
[self dismissViewControllerAnimated:YES completion:NULL];
if ([self.capturedImages count] > 0)
{
if ([self.capturedImages count] == 1)
{
// Camera took a single picture.
[self.photo2View setImage:[self.capturedImages objectAtIndex:1]];
}
// To be ready to start again, clear the captured images array.
[self.capturedImages removeAllObjects];
}
self.imagePickerController = nil;
}
Anyone know how to fix this?
I saw your questions an couldn't help my self to solve it in my way. If I had same problem as yours I would have solved it in this way:
Consider, button's tag is same as, imageView tag.
#import "ViewController.h"
#interface ViewController ()
- (IBAction)takePhoto:(id)sender;
#property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *imageViews;
#property int tag;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)takePhoto:(id)sender {
_tag = ((UIButton *)sender).tag;
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:nil];
}
#pragma mark - UIImagePickerDelegate Methods
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
[picker dismissViewControllerAnimated:NO completion:nil];
[[self getImageView:_tag] setImage:image];
}
- (UIImageView *) getImageView : (int) tag{
for (UIImageView *imageView in _imageViews) {
if (imageView.tag == tag) {
return imageView;
}
}
return nil;
}
#end
Here you can check this as working project here.
Check your storyboard or xib to see if "photo2View" is really connected to your outlet.
I suspect the UIImageView for "photo1View" is also connected to "photo2View".
p.s. you should also change this line in your #implementation:
- (void)takePhoto2;
to this:
- (void)takePhoto2
semi-colons should only come after method declarations in your .h file.
Does your code work? I find two issues -
Issue 1 - This should crash as capturedImages has one element according to second if check but you are accessing second element in the array while setting the imageView.
if ([self.capturedImages count] == 1)
{
// Camera took a single picture.
[self.photo2View setImage:[self.capturedImages objectAtIndex:1]];
Issue 2 - Since you are clearing the self.capturedImages, this should have thrown you can exception in second method.
[self.photo2View setImage:[self.capturedImages objectAtIndex:1]];
Did you properly connect button 1 to takePhoto1 and button 2 to takePhoto2? Maybe button 2 is also doing takePhoto1?

How could I use a single UIButton to get a library photo with an image picker and perform a push segue?

I am trying to pick an image from the photo library and perform a segue only if the user selects an image. (Does nothing if the user presses cancel)
Is it possible to pack all of this action into one single button press via IBAction?
The issue I am facing with my attempted code is that it tries to perform the push segue right when I press the button, which apparently is at the same time I am trying to access the photo library. I can't figure out how to get the image picker to go first and then have the push segue trigger immediately after, depending on whether an image was picked or the process was canceled.
ViewController.m
- (IBAction)LibraryButton:(id)sender
{
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imagePicker animated:YES completion:nil];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"takeLibraryPhoto"])
{
buffer = modBuffer;
selectDisplayViewController *secondVC = [segue destinationViewController];
}
else if ([segue.identifier isEqualToString:#"takeCameraPhoto"])
{
}
else if ([segue.identifier isEqualToString:#"takeCameraVideo"])
{
}
}
- (BOOL) shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if([identifier isEqualToString:#"takeLibraryPhoto"])
{
//[self presentViewController:imagePicker animated:YES completion:nil];
if(modBuffer != NULL)
{
return true;
}
return false;
}
else
{
return true;
}
return false;
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
/*UIImage *loadImage;
loadImage = [info valueForKey:UIImagePickerControllerOriginalImage];
buffer = loadImage;*/
modBuffer = [info valueForKey:UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad
{
imagePicker = [[UIImagePickerController alloc]init];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
selectDisplayViewController.m
#implementation selectDisplayViewController
#synthesize selectDisplayView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
selectDisplayView.image = buffer;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
What my code currently does is... When I load an image, "buffer" of selectDisplayViewController is successfully getting data from "modBuffer", but by then the push segue has already occurred and it returns me to the original view controller that I press the button from. It isn't until I press the button a second time (could also press cancel this time) that it takes me to the other view controller where it displays my image.
I have been struggling with this for many days now. How can I get this to behave more like a sequence where its a step process instead of the push segue happening right away!! :(
All help is greatly appreciated. Thanks :)
Not really sure I completely follow but it sounds like you want to perform the segue after the user selects a picture or presses cancel from the image picker.
If that's the case then you can do that in the delegate methods using [self performSegueWithIdentifier:#"foo" sender:nil];

Resources