Still Dismissing Alert - objective-c

I am trying to keep this UIAlertView up after the presses either of the buttons (1 & 2).
Once i click on the "+" button or the "-" button, I can see the UILabel text increment, then it closes the UIAlertView.
This is what i currently am using:
#pragma Alert View Methods
-(void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
{
[self dismissWithClickedButtonIndex:buttonIndex animated:animated];
}
#pragma count functions
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1 || buttonIndex == 2) {
return;
}
else{
[self dismissWithClickedButtonIndex:buttonIndex animated:YES];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
self.currentCountButtonCount++;
[self.countAlert setMessage:[NSString stringWithFormat:#"%d",self.countButtonCount + 1]];
}if (buttonIndex == 2) {
self.currentCountButtonCount--;
[self.countAlert setMessage:[NSString stringWithFormat:#"%d",self.countButtonCount - 1]];
}
}
- (IBAction)countClick:(id)sender {
// tallies and keeps current count number
if (!self.currentCountButtonCount)
self.currentCountButtonCount = 0;
NSString *alertMessage = [NSString stringWithFormat:#"%d", self.countButtonCount];
self.countAlert = [[UIAlertView alloc]initWithTitle:#"Count" message:alertMessage delegate:self cancelButtonTitle:#"end" otherButtonTitles:#"+",#"-", nil];
[self.countAlert show];
}
On my last question someone told me to do it custom and this is what im trying now and it still dismisses the UIAlert.
How can i keep it up while the label changes until they touch the end button?

What are you using is default button of AlertView and after click on that button it will automatically dismissed the alertview.
So you have to create your buttons programatically and add that buttons in your alertview like:
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[btn setTitle:#"+" forState:UIControlStateNormal];
[countAlert addSubview:btn ];
on this btn call your method.
So you have to create two custom button with "+" and "-". and add that buttons in AlertView.
-(void)setAlertValue:(id)sender{
switch ([sender tag]) {
case 1:
{
// currentCountButtonCount++;
[self.countAlert setMessage:[NSString stringWithFormat:#"%d",++countButtonCount]];
}
break;
case 2:
{
//currentCountButtonCount--;
[self.countAlert setMessage:[NSString stringWithFormat:#"%d",--countButtonCount]];
}
break;
default:
break;
}
}
- (IBAction)countClick:(id)sender {
// tallies and keeps current count number
if (!currentCountButtonCount)
currentCountButtonCount = 0;
NSString *alertMessage = [NSString stringWithFormat:#"%d", countButtonCount];
self.countAlert = [[UIAlertView alloc]initWithTitle:#"Count" message:alertMessage delegate:self cancelButtonTitle:#"end" otherButtonTitles:nil, nil];
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(10, 50, 40, 20)];
[btn addTarget:self action:#selector(setAlertValue:) forControlEvents:UIControlEventTouchUpInside];
[btn setBackgroundColor:[UIColor greenColor]];
btn.tag = 1;
[btn setTitle:#"+" forState:UIControlStateNormal];
UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(230, 50, 40, 20)];
[btn1 addTarget:self action:#selector(setAlertValue:) forControlEvents:UIControlEventTouchUpInside];
[btn1 setBackgroundColor:[UIColor redColor]];
btn1.tag = 2;
[btn1 setTitle:#"-" forState:UIControlStateNormal];
[countAlert addSubview:btn];
[countAlert addSubview:btn1];
[self.countAlert show];
}

I don't want to rain in your parade, but if you think that an alert view is the best way to handle an increment/decrement of a variable, I would suggest you to reconsider your design.
UIAlertViews are meant for transient information and simplified decision making. A simple "Are you sure?" is the text-book example of an alert view usage.
From the user stand point, it's much more comforting being able to modify all the attributes in sliders or any other form of permanent input, and then, when sure, hit the confirm button with an alert view (or confirmation screen). Doing it in an Alert view is not only error prone, but counter-intuitive compared in the way that the rest of iOS works.
If you're having trouble on fitting another form of input in your application, please read on how to perform animations and reveal control as they are needed, hiding the input inside an UIAlertView is simply the easiest solution for you, but not the best for the user.

Related

Actionsheet buttons do not respond when using showInView

I have this code on my program
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *saveMessageBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[saveMessageBtn setImage:[UIImage imageNamed:#"btn_done.png"] forState:UIControlStateNormal];
[saveMessageBtn addTarget:self action:#selector(saveMessage) forControlEvents:UIControlEventTouchUpInside];
[saveMessageBtn setFrame:CGRectMake(0, 0, 49, 30)];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:saveMessageBtn];
}
-(IBAction)saveMessage:(id)sender{
UIActionSheet *actionSheet = [[UIActionSheet alloc]initWithTitle:nil delegate:nil cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Send Now",#"Non Recurring",#"Recurring", nil];
[actionSheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *) actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0){
NSLog(#"Send Now");
}
else if (buttonIndex == 1){
[self performSegueWithIdentifier:#"modalNonRecurring" sender:self];
}
else if (buttonIndex == 2){
[self performSegueWithIdentifier:#"modalRecurring" sender:self];
}
else{
NSLog(#"Cancel Clicked");
}
}
as you can see in the code, it supposed to perform a segue or do 'NSLog' when a particular button clicked.
But when I click a button, it does not perform what I want it to do, instead it displays this message in the debug area..
Presenting action sheet clipped by its superview. Some controls might not respond to touches. On iPhone try -[UIActionSheet showFromTabBar:] or -[UIActionSheet showFromToolbar:] instead of -[UIActionSheet showInView:].
By the way, I am using a UINavigationController that is inside a UITabBarController.
Anyone that has a great idea how to fix this? your help would be much appreciated. Thanks!
Add UIActionSheetDelegate delegate in .h file and try like this then it'l work.
UIActionSheet *actionSheet = [[UIActionSheet alloc]initWithTitle:nil delegate:nil cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Send Now",#"Non Recurring",#"Recurring", nil];
actionSheet.delegate = self;
[actionSheet showInView:self.view];

Change a label on cells of UITableView?

I've added 3 labels and a button on cell of UITableView like this image
when i click on checkbox i change the label 'Due in 0 days' in some other stuff. it is ok with this code
[statusText setTextColor:[UIColor colorWithRed:0.0/255.0 green:51.0/255.0 blue:102.0/255.0 alpha:1.0]];
[statusText setFont:[UIFont boldSystemFontOfSize:16.0]];
statusText.tag = 100;
[statusText setBackgroundColor:[UIColor clearColor]];
[checkBoxBtn setBackgroundImage:[UIImage imageNamed:#"check_normal.png"] forState:UIControlStateNormal];
[checkBoxBtn addTarget:self action:#selector(showAlert:) forControlEvents:UIControlEventTouchUpInside];
checkBoxBtn.tag = indexPath.row;
[cell.contentView addSubview:checkBoxBtn];
this is my checkBoxAction and showAlert methods
-(void) checkBoxAction: (UIButton *)sender
{
NSInteger i =sender.tag + 1;
float perc = (i*100/18.0);
//NSLog(#"%.2f",perc);
NSString* percentageStr = [[NSString alloc] initWithFormat:#"%3.2f%%(%d out of 18)",perc, i];
barTitle.text = percentageStr;
barFGImage.hidden = NO;
if (perc == 100.00) {
[barFGImage setFrame:CGRectMake(barFGImage.frame.origin.x, barFGImage.frame.origin.y, 276.0, barFGImage.frame.size.height)];
}
else
[barFGImage setFrame:CGRectMake(barFGImage.frame.origin.x, barFGImage.frame.origin.y, 280*perc/100, barFGImage.frame.size.height)];
[sender setBackgroundImage:[UIImage imageNamed:#"check_select.png"] forState:UIControlStateNormal];
sender.userInteractionEnabled = NO;
NSString *currentDate = [formatter stringFromDate:[NSDate date]];
NSString* statusStr = [[NSString alloc] initWithFormat:#"Completed on %#",currentDate];
UILabel *tempLabel = (UILabel *)[[button superview] viewWithTag:100];
tempLabel.textColor = [UIColor colorWithRed:243.0/255.0 green:134.0/255.0 blue:48.0/255.0 alpha:1.0];
tempLabel.text = statusStr;
}
- (void) showAlert:(id)sender
{
button = (UIButton *)sender;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"" message:#"Do you really want to complete this training?" delegate:self cancelButtonTitle:#"Yes, I've completed it" otherButtonTitles: #"No", nil];
[alert show];
}
Now i want that if i press checkBox on row (say)3rd then 'Due in 0 days' label of row 3rd, 4th and so on should changed.Any suggestion or sample code will be appreciated.
Thanks.
I am afraid my suggestion is not going to be a simple suggestion or code sample, but rather I would invite you to spend some time reading about MVC (Model View Controller).
From what I can tell from your code, your data seems to be 'stored' in your view objects. This is a very bad idea in general, this is a terrible idea with table views, as cells are being reused, and your data would just disappear as you scroll through large tables.
What you need to do is define model classes to hold your data, the controller objects will then access those model objects and display their data in the various views they control.
Once you implement this kind of pattern, checking something in one cell will update your model objects. Then all you will need to do is to make a simple [tableView reloadData]; call to update ALL your cells at once.

Call UIAlertView delegate method with parameter?

I've added a button on cell of my table view like this-
UIButton* checkBoxBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBoxBtn setBackgroundImage:[UIImage imageNamed:#"check_normal.png"] forState:UIControlStateNormal];
[checkBoxBtn addTarget:self action:#selector(checkBoxAction:) forControlEvents:UIControlEventTouchUpInside];
checkBoxBtn.tag = indexPath.row;
[cell.contentView addSubview:checkBoxBtn];
and this is my checkBoxAction
-(void) checkBoxAction: (UIButton *)sender
{
NSInteger i =sender.tag + 1;
float perc = (i*100/18.0);
NSLog(#"%.2f",perc);
NSString* percentageStr = [[NSString alloc] initWithFormat:#"%3.2f%%(%d out of 18)",perc, i];
barTitle.text = percentageStr;
barFGImage.hidden = NO;
if (perc == 100.00) {
[barFGImage setFrame:CGRectMake(barFGImage.frame.origin.x, barFGImage.frame.origin.y, 276.0, barFGImage.frame.size.height)];
}
else
[barFGImage setFrame:CGRectMake(barFGImage.frame.origin.x, barFGImage.frame.origin.y, 280*perc/100, barFGImage.frame.size.height)];
[sender setBackgroundImage:[UIImage imageNamed:#"check_select.png"] forState:UIControlStateNormal];
sender.userInteractionEnabled = NO;
}
And every thing OK for now, but i want to show an alert when user press checkBoxBtn and if user press OK then the checkBoxAction should called.I know we have UIAlertView delegate method
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
But problem is that how to get checkBoxBtn in it?
EDIT: It is OK with Midhun MP's answer, but i want one more thing- in my cell i have three labels and a button , with the click on check box i want to change label 'Due in 6 days' along with other stuff that we done in my checkBoxAction method
Please help me. Thanks.
For achieving this you need to implement the - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex delegate method.
You can do it like:
Declare a UIButton instance in .h
like:
UIButton *button;
Change the button adding method like:
UIButton* checkBoxBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBoxBtn setBackgroundImage:[UIImage imageNamed:#"check_normal.png"] forState:UIControlStateNormal];
[checkBoxBtn addTarget:self action:#selector(showAlert:) forControlEvents:UIControlEventTouchUpInside];
checkBoxBtn.tag = indexPath.row;
[cell.contentView addSubview:checkBoxBtn];
- (void) showAlert:(id)sender
{
button = (UIButton *)sender
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: #"Cancel"];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0)
{
[self checkBoxAction:button];
}
}
For getting the label:
Add a tag to the label in cellForRowAtIndexPath: like:
statusText.tag = 7;
[cell.contentView addSubview:statusText];
And you can get the label using the following code:
UILabel *tempLabel = (UIlabel *)[[button superview] viewWithTag:7];
tempLabel.text = #"Midhun";

Detect which uitextfield called the uikeyboard

After a lot of trouble I was able to add a RETURN button to a numerical key pad.
I want to delete it when introduciing other data into other uitextfields because currently that button appears everytime I use the keyboard, it's part of the keyboard.
Im adding the event handler on KeyBoardDidShow, otherwise it doesnt work,
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
Then in KeyboarWillShow
- (void)keyboardWillShow:(NSNotification *)note {
// create custom button
NSLog(#"El note es: %#", note);
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"done.jpg"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"done_pressed.jpg"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
if (!keyboardWindow) return;
// Locate UIKeyboard.
UIView *foundKeyboard = nil;
for (UIView *possibleKeyboard in [keyboardWindow subviews]) {
// iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
if ([[possibleKeyboard description] hasPrefix:#"<UIPeripheralHostView"]) {
possibleKeyboard = [[possibleKeyboard subviews] objectAtIndex:0];
}
if ([[possibleKeyboard description] hasPrefix:#"<UIKeyboard"]) {
foundKeyboard = possibleKeyboard;
break;
}
}
if (foundKeyboard) {
// Add the button to foundKeyboard.
[foundKeyboard addSubview:doneButton];
}
}
The thing is that this creates the button always! Obviously! I would like to create the button only in certains uitextfields, not in all, but how to do that?
The method - (BOOL)textFieldShouldBeginEditing: doesnt execute the first time, only the rest, why? Dont know, but if I was able to know which uitextfield is calling the keyboard my hair would grow again and I'd be slimmer, anyone can help?
textFieldShouldBeginEditing: only fires consistently if each and every one of your text fields have delegates set properly (check your XIB).
And then you can set a tag value in your text fields. You can display the Return button for fields with tag 1 and no Return button for fields with tag 0.
You can try to count the number of subviews inside the keyboard to know how many keys it has. That is a bad hack, but you already have a bad hack to find the keyboard :-)
Also another suggestion:
if (foundKeyboard) {
UIView *doneButton = [foundKeyboard viewWithTag:BUTTON_TAG];
if(numPad){
if(buttonView==nil){
//create doneButton
[foundKeyboard addSubview:doneButton];
}
}else{
[doneButton removeFromSuperview];
}
}

UIAlert partially hidden on iPad horizontal orientation. How to move it up?

In my iPad app, I have an implementation of a login window as a UIAlertView subclass that adds two UITextField, using an idiom that's found on the net.
The problem is that in horizontal orientation, the alert is partially hidden by the keyboard. Namely, the buttons are hidden. Of course, it's possible to hide the keyboard to reveal the button, but this is ugly.
The way the idiom is supposed to fix that is to add a translation transform to the view:
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 100.0);
[self setTransform:translate];
However that doesn't really work:
in initial vertical orientation, that works (but stops working after any device rotation)
in initial horizontal orientation, one can see it work, but the alert is right away animated back to the center of the screen where it's partially hidden again.
in any orientation after rotating the iPad, it doesn't work at all: nothing happens, as if the transform was not even there.
(additionally, this transform idea may stop {working|being necessary} for iOS 4.x. But that's another issue).
Any idea welcome.
For the sake of completeness, here is the full code:
- (id)initWithLogin:(NSString *)defaultLogin delegate:(id)delegate
{
if (self = [super initWithTitle:#"Username and password"
message:#"\n\n\n"
delegate:delegate
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Enter", nil])
{
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 45.0, 260.0, 25.0)];
[theTextField setBackgroundColor:[UIColor whiteColor]];
theTextField.text = defaultLogin;
theTextField.placeholder = #"username";
[self addSubview:theTextField];
self.loginField = theTextField;
[theTextField release];
theTextField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 80.0, 260.0, 25.0)];
[theTextField setBackgroundColor:[UIColor whiteColor]];
theTextField.placeholder = #"password";
theTextField.secureTextEntry = YES;
[self addSubview:theTextField];
self.passwordField = theTextField;
[theTextField release];
// the two next lines may not be useful for iOS > 4.0
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 100.0);
[self setTransform:translate];
}
return self;
}
Thanks for Bittu for a working solution. Here is my implementation of his idea. I put the code to move the alert up in a new method of my subclass:
- (void)slideUp
{
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.25f];
CGPoint center = self.center;
center.y -= 100;
self.center = center;
[UIView commitAnimations];
}
The key point is when to call that code. There are two cases: the simplest case is when the user rotates the device. Unfortunately, the Alert class is not informed of that event, only the client UIViewController, so that's were we need to call it. This is ugly by breaking encapsulation, but so be it:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(loginWindow && UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
[loginWindow slideUp];
}
}
The second case is when the orientation is already horizontal when opening up the alert. The alert delegate is informed of that in its didPresentAlertView: delegate method.
- (void)didPresentAlertView:(UIAlertView *)alertView
{
if ( UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ) {
[self slideUp];
}
}
Unfortunately, that implementation doesn't work, because calling slideUp at that time will conflict with the system already animating the alert to the center of the screen. The solution is to delay the call slightly, for example using NSTimer:
- (void)didPresentAlertView:(UIAlertView *)alertView
{
if ( UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ) {
[NSTimer scheduledTimerWithTimeInterval:0.25f
target:self
selector:#selector(slideUp)
userInfo:nil
repeats:NO];
}
}
By the way, slideUp doesn't have the documented signature for a NSTimer selector, but it still seems to work! If that bothers you, simply add an in between method with the correct signature:
- (void)slideUpByTimer:(NSTimer*)theTimer
{
[self slideUp];
}
I had the exact same issue with the alertView with UITextField as a subview. Instead of taking the transform path, I took a little different approach. Here's how I did it.
First create your alertview with textfield in it:
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 40.0, 260.0, 25.0)];
[textField setBackgroundColor:[UIColor whiteColor]];
textField.placeholder = #"Search";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Enter Search Text" message:#" " delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Enter",nil];
[alertView addSubview:textField];
[alertView show];
Then in the UIViewController that's going to show the alert view, implement this method:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.25f];
CGPoint center = self.alertView.center;
center.y -= 100;
self.alertView.center = center;
[UIView commitAnimations];
}
}
this method happens after the "rotation finished" notification has been posted. therefore, you'll see the alertview partially under the keyboard before the animation to slide it up starts happening. Hope this helps you with your login alertview.