I have an action sheet that when one of it's options are clicked successfully calls clickedButtonAtIndex when run in the simulator but when testing on an iPhone (5s in Xcode 6) it doesn't reach the callback.
The header...
#protocol SGETriggerToolBarDelegate
-(void)showCustomEditView;
#end
#interface SGETriggerToolBarController : UIViewController <UIActionSheetDelegate>
#property (nonatomic, assign) id <SGETriggerToolBarDelegate> delegate;
#property (nonatomic, strong) UIToolbar *toolbar;
in the implementation...
// in xController.m
// ...
- (void)triggerButtonHandler
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Select an event type"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
for (SGETrigger *trigger in triggers) {
[actionSheet addButtonWithTitle:trigger.name];
}
[actionSheet addButtonWithTitle:#"Cancel"];
actionSheet.cancelButtonIndex = triggers.count;
[actionSheet showFromToolbar:self.toolbar];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == [actionSheet cancelButtonIndex]) {
return;
} else {
selectedTrigger = triggers[buttonIndex];
triggerButton.title = [NSString stringWithFormat:#"• %# •", selectedTrigger.name];
[delegate showCustomEditView];
}
}
// ...
If you get "Presenting action sheet clipped by its superview. Some controls might not respond to touches"
Replacing...
[actionSheet showFromToolbar:self.toolbar];
with
[actionSheet showInView:[UIApplication sharedApplication].keyWindow];
solved this for me.
Related
I have been trying to make an app that allows the user to retrieve the current location using the core location framework. I wanted to be able to get the coordinates of the device that is using the app when the app launches and be able to display them using UILabels. Can someone please tell me what i am doing wrong or what adjustments I should make to the code?
Header file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *longitude;
#property (strong, nonatomic) IBOutlet UILabel *latitude;
#property (strong, nonatomic) IBOutlet UILabel *altitude;
#property (strong, nonatomic) IBOutlet UILabel *speed;
#end
Implementation file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
CLLocationManager *locationManager;
[super viewDidLoad];
locationManager = [[CLLocationManager alloc]init]; // initializing locationManager
locationManager.delegate = self; // I set the delegate of locationManager to self.
locationManager.desiredAccuracy = kCLLocationAccuracyBest; // setting the accuracy
[locationManager startUpdatingLocation]; //requesting location updates
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error" message:#"There was an error retrieving your location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[errorAlert show];
NSLog(#"Error: %#",error.description);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *crnLoc = [locations lastObject];
_latitude.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.latitude];
_longitude.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude];
_altitude.text = [NSString stringWithFormat:#"%.0f m",crnLoc.altitude];
_speed.text = [NSString stringWithFormat:#"%.1f m/s", crnLoc.speed];
}
#end
I get these 2 errors.
Assigning to 'id<CLLocationManagerDelegate> _Nullable' from incompatible type 'ViewController *const __strong'
'UIAlertView' is deprecated: first deprecated in iOS 9.0 - UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead
You're not implementing the CLLocationManagerDelegate protocol, which is why you get the first error. You could implement it like this:
#interface ViewController () <CLLocationManagerDelegate>
#end
You should also check the documentation for the methods that you'll need to implement in order to conform to that protocol, which you'll have to write in your #implementation. Only after conforming to that protocol is this assignment allowed:
locationManager.delegate = self; // I set the delegate of locationManager to self.
The second issue appears to be a warning. Apple did deprecate UIAlertView in iOS 9.0 and it has been replaced by UIAlertController, so you should use that instead. This NSHipster article explains how to use and compares it with the old, deprecated, version, which is interesting, but it's in Swift (I'm leaving it for the discussion they present). Here you'll also find some examples in Objective-C. Here's an example as shown on that last link:
UIAlertController * view= [UIAlertController
alertControllerWithTitle:#"My Title"
message:#"Select you Choice"
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* ok = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Do some thing here
[view dismissViewControllerAnimated:YES
completion:nil];
}];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[view dismissViewControllerAnimated:YES completion:nil];
}];
[view addAction:ok];
[view addAction:cancel];
[self presentViewController:view animated:YES completion:nil];
I want to reset the textfields of myview to empty when an actionsheet destructive button is pressed. Done button calls the actionsheet.
This is my actionsheet:
- (IBAction)submit:(id)sender {
UIActionSheet *sheet=[[UIActionSheet alloc]initWithTitle:#"Options" delegate:sender cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Reset" otherButtonTitles:#"Save", nil];
[sheet showInView:self.view];
}
And is used this method to reset:
- (void)sheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==0)
{
self.textf1.text = #"";
}
}
But Nothing is happening.
Replace delegate:sender to delegate:self that's why delegates
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
are not getting call also update the delegate function, once you done just set all textFiled to .text= #"". i hope it will work
Also posted as Comment earlier.
delegate method you are using is worng
Please make your delegate to self
delegate:self
and Use this method
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
////check index and empty all textfields
}
You should set self as the delegate, and I think the new UIAlertController is more convenience to use, without any delegate:
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:#"Action Sheet" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *reset = [UIAlertAction actionWithTitle:#"Reset" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
self.textf1.text = #"";
}];
actionSheet.actions = #[reset, cancel];
[self presentViewController:actionSheet animated:YES completion:nil]
Lots of issues:
Change this line:
if (buttonIndex == 0)
to:
if (buttonIndex == sheet.destructiveButtonIndex)
You also need to pass self as the delegate instead of sender.
UIActionSheet *sheet= [[UIActionSheet alloc] initWithTitle:#"Options" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Reset" otherButtonTitles:#"Save", nil];
And the name of the delegate method matters. You need:
- (void)actionSheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)buttonIndex
See the docs for UIActionSheet. There are specific properties to get various button indexes. Use those over hardcoding index numbers.
Also note that UIAlertView is deprecated. You should be using UIAlertController unless you need to support iOS 7.
#import "ViewController.h"
#interface ViewController ()<UITextFieldDelegate,UIActionSheetDelegate>
{
UIActionSheet *sheet;
}
#property (weak, nonatomic) IBOutlet UITextField *txtText;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
//Button click
- (IBAction)OpenActionSheet:(id)sender
{
sheet=[[UIActionSheet alloc]initWithTitle:#"ActionSheetDemo" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Reset" otherButtonTitles:#"Save", nil];
[sheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex==0)
{
_txtText.text=#"";
}
}
#end
My Method where the acton sheet is called
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[txtSourceTime resignFirstResponder];
UIActionSheet *sheet1 = [[UIActionSheet alloc] initWithTitle:#"Select Source time" delegate:self cancelButtonTitle:nil destructiveButtonTitle:#"Cancel" otherButtonTitles:#"Done", nil];
[sheet1 setActionSheetStyle:UIActionSheetStyleDefault];
[sheet1 setTag:3];
[sheet1 showInView:self.view];
time = [[UIDatePicker alloc] init];
time.datePickerMode = UIDatePickerModeDateAndTime;
time.timeZone = [NSTimeZone localTimeZone];
[time setBounds:CGRectMake(0, -125, 320, 200)];
[sheet1 addSubview:time];
[sheet1 showFromRect:CGRectMake(0, 300, 320, 300) inView:self.view animated:YES];
[sheet1 setBounds:CGRectMake(0, 0, 320, 500)];
}
Unable to get the date in the textbox when i click done in actionsheet
Need to add an UIActionSheetDelegate method to know when the Done button is tapped and then update the UITextField with the date from the UIDatePicker. E.g.:
In the .h:
Add the UIActionSheetDelegate protocol:
#interface MyClass : UIViewController <UIActionSheetDelegate, UITextFieldDelegate>
// ...
#end
In the .m:
Add UIActionSheet delegate method to know when action sheet is being dismissed (i.e., one of the buttons is tapped):
-(void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex{
// buttonIndex of 1 is the Done button
if (buttonIndex == 1) {
NSDate *date = time.date;
// Date shows in text field, but is not nicely formatted
textField.text = date.description;
}
}
and set the delegate for the UIActionSheet:
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
//...
UIActionSheet *sheet1 = [[UIActionSheet alloc] initWithTitle:#"Select Source time" delegate:self cancelButtonTitle:nil destructiveButtonTitle:#"Cancel" otherButtonTitles:#"Done", nil];
sheet1.delegate = self;
//...
}
Do note that per Apple's documentation, this is not the recommended use of an UIActionSheet:
UIActionSheet is not designed to be subclassed, nor should you add
views to its hierarchy.
Another alternative is to add the UIDatePicker as the inputView on the UITextField. For the Cancel and Done buttons, add an inputAccessoryView on the UITextField (which would show at the top of the UIDatePicker.
Add below code.....
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
printf("\n cancel");
}else{
printf("\n Done");
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy HH:mm"];
NSString *strDate = [dateFormatter stringFromDate:time.date];
_txtSourceTime.text = strDate;
}
}
If the "button/checkbox" I have created below is selected by the user on view controller 1, then I would like an image to (appear) display on view controller 2.
if i leave view controller 2 screen and come back to view controller 2 screen, the image should still display as long as the button is still selected on view controller 1.
if the "button" is no longer selected on view controller 1, then the image should no longer be displayed on view controller 2.
Please note that the "button/checkbox" mentioned is being created by the code below. Please help, thank you.
(IBAction)checkButton2:(id)sender {
if (!checked2) {
[_checkBoxButton2 setImage:[UIImage imageNamed:#"checkBoxMarked.png"] forState:UIControlStateNormal];
checked2 = YES;
// alert placeholder
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Locked" message:#"this is locked." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:#"Cancel", nil];
[alert show];
[_checkBoxButton2 setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
checked2 = NO;
}
else if (checked2) {
[_checkBoxButton2 setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
checked2 = NO;
// alert placeholder
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Character selection:" message:#"The box is no longer selected." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:#"Cancel", nil];
[alert show];
}
}
You should Embed you View into a navigation controller.
When you press Next Screen, perform a segue:
- (IBAction)nextBtn:(id)sender {
[self performSegueWithIdentifier:#"segue" sender:self];
}
before you segue, set a BOOL flag to determine if it should display or not:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"step2Segue"]){
ImageViewController *controller = (ImageViewController *)segue.destinationViewController;
controller.displayImage = checked2;
}
}
Finaly in the ImageViewController add a condition based on the Bool to determine if you should display it or not:
in .h
#interface ImageViewController : ViewController
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (nonatomic, assign) BOOL displayImage;
#end
In .m
-(void)viewDidLoad{
if (self.displayImage) {
self.image.hidden = YES;
}else{
self.image.hidden = NO;
}
}
One thing at a time.
In the ViewController1 class, you'll have to have an instance of ViewController2 created and made strong in your .h (if you're not using Swift).
#property (nonatomic, strong) ViewController2 *viewController2;
Make sure it's instantiated at the time that you press the button. Within the .h for ViewController 2, you'll have to do something similar with a UIImage and UIImageView or whatever you use to display the picture
#property (nonatomic, strong) UIImage *myImage;
#property (nonatomic, strong) UIImageView *myImageView;
Then, in ViewController1, you'll have to control the events that happen in ViewController2 when you press the button. I would use a BOOL or something else simple to keep track of when the image is supposed to be visible.
BOOL imageShouldBeThere = false;
- (void) myButtonWasPressed: (id) sender
{
if(imageShouldBeThere == false)
{
[viewController2Instance showTheImage];
imageShouldBeThere = true;
}
else
{
[viewController2Instance hideTheImage];
imageShouldBeThere = false;
}
}
This is obviously just a rudimentary template, but it should do the trick.
Working code:
FirstViewController.m
- (IBAction)buttonClicked:(id)sender {
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"second"];
secondViewController.shouldShowImage = YES;
[self presentViewController:secondViewController animated:YES completion:^{
}];
}
SecondViewController.h
#property (nonatomic, assign) BOOL shouldShowImage;
SecondViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.shouldShowImage)
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
[imageView setImage:[UIImage imageNamed:#"9gag.png"]];
[self.view addSubview:imageView];
}
else
{
//dont show image....
}
}
Some of my ViewController.h
NSString *title1;
NSString *sub1;
#interface MapMain : UIViewController
{
IBOutlet UIButton *setter;
}
All within the same ViewController.m
-(IBAction)Write:(id)sender
{
[self alertView];
}
-(void)alertView
{
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#""
message:#"Your Info"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Done", nil];
alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
UITextField * alertTextField1 = [alert textFieldAtIndex:0];
alertTextField1.keyboardType = UIKeyboardTypeDefault;
alertTextField1.placeholder = #"Name";
UITextField * alertTextField2 = [alert textFieldAtIndex:1];
alertTextField2.keyboardType = UIKeyboardTypeDefault;
alertTextField2.placeholder = #"Username";
alertTextField2.secureTextEntry = NO;
[alert show];
}
So this code correctly makes a pop up appear with two text fields when I click on a specific button. How can I store the text the user inputs when they press the "Done" button into my NSString *title1 and NSString *sub1 respectfully, so that I can use the string values when other buttons are pressed later. And how can I make my program not store the text when the user presses the "Cancel" button?
Make your MapMain class conform to the UIAlertViewDelegate protocol
#interface MapMain : UIViewController <UIAlertViewDelegate>
and then implement the delegate's method for when the alert is dismissed like this
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) //only if cancel is not clicked (done is clicked)
{
UITextField * alertTextField1 = [alertView textFieldAtIndex:0];
UITextField * alertTextField2 = [alertView textFieldAtIndex:1];
//... do whatever else you need to here like
title1 = alertTextField1.text;
}
}