I have view with text field -- subclassed from UIAlertView. In the textFieldShouldReturn delegate I call resignFirstResponder for text field and dismissWithClickedButtonIndex for view. On the 3.x version everything fine, but on 4.0 keyboard still present on screen after view dismissing and doesn't disappear while app running. App compiled for 3.0 target and tested on 4.0 iPhone OS. One more thing - sometimes after dismissing alert - Done button on the keyboard replaces with Return button.. Any suggestions ?
Strange thing.. I wrote functions to find and animate out keyboard view by timer but keyboard can't be found while it present on the screen..
Something like this:
for( UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows] ){
for( UIView *keyboard in [keyboardWindow subviews] ){
NSString *desc = [keyboard description];
if( [desc hasPrefix:#"<UIKeyboard"]==YES ) {
// animate out
}
}
}
What is canResignFirstResponder returning? I had the same problem you describe going to 4.0, fixed it by paying more attention to this function. If you're returning NO, try YES - sort out the conditions later if you find this has the desired effect.
Related
We all know how to add custom button (usually it's Done) above normal numeric pad on iPhone. There were few questions related to this:
how to get keyboard location in ios 8 & add DONE button on numberPad
Can't find keyplane that supports type 4 for keyboard iPhone-Portrait-NumberPad; using 3876877096_Portrait_iPhone-Simple-Pad_Default
they work fine before iOS9. iOS9 broke that existing keyboard view hierarchy and above mentioned solutions don't work anymore. I've spend few hours trying to figure out the difference, and decided to post it here as it might be useful for other people.
The difference from the solution that worked for iOS7-8 is the following:
// Note index 2 here! In pre-iOS8 keyboard view panel was under second window after UIWindow, in iOS9 - they put some other views on the place and shifted everything one element down.
UIWindow *tempWindow = [[[UIApplication sharedApplication] windows][2];
UIView *keyboard;
for (int i = 0; i < [tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
// keyboard view found; add the custom button to it
if ([[keyboard description] hasPrefix:#"<UIPeripheralHostView"] == YES)
{
[keyboard addSubview:doneButton];
}
}
This is the current setup.
I have the navigationController's toolbar with 5 buttons, and tapping on them hides the toolbar for 2 seconds, and then shows the toolbar again (except the 5th button - which brings up an actionsheet with buttons (ACTION & CANCEL)).
On tapping on the 1-4 buttons, I do a self.navigationController.toolbarHidden = YES; and after exactly 2 seconds, I set the self.navigationController.toolbarHidden = NO; and this brings back the toolbar, and everything's fine.
On tapping the 5th button, which brings up action sheet.
If i tap on CANCEL actionsheet => actionSheet dismissed => Toolbar is fine.
If I tap on ACTION button I do a self.navigationController.toolbarHidden = YES; and after 2 seconds... self.navigationController.toolbarHidden = NO;
but now... The toolbar buttons are GONE.
Further investigating...
I can see the the toolbarButtons seem to have their alpha values set to 0.
I have no idea why the toolbar items' alpha are set to value = 0 after actionsheet operation.
Can anyone tell me the root cause for this?
Have you tried setting the toolbar items array to nil? I had this same problem and it turned out that putting a check around when you set the toolbar's items seemed to work:
if ([self.navigationController.toolbar.items count] > 0) {
[self.navigationController.toolbar setItems:nil];
}
[self.navigationController.toolbar setItems:toolbarItems]; //toolbarItems is your array of UIBarButtonItems.
I managed to fix the issue in a different way. I hide the toolbar when the action sheet comes up, and after the buttonAction(), I essentially show the toolbar again.
This solves the problem where the toolbarItems disappear.
But the reason as to why the toolbarItems disappear and set alpha=0 is still a mystery for me. If anyone finds out the reason, please let me know :)
I had the same issue and reproduced it in one of the samples. It appears to be a bug in iOS6 when setting up toolbar items manually in loadView / viewDidLoad, then later calling an ActionSheet.
The code below is a workaround it -
-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSArray* items = self.toolbarItems;
[self setToolbarItems:nil];
[self setToolbarItems:items animated:NO];
}
I solve it by moving action code to separate method and then calling it through sending message performSelector:withObject:afterDelay: with 0.25f second delay
Example:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self performSelector:#selector(logout) withObject:nil afterDelay:0.25f];
}
}
I don't know if it's the case, I found out that the disappeared items were actually in the toolbar, but placed over the bottom of the view. Maybe resetting them on certain circumstances may cause autolayout issues.
I fixed it by calling the setNeedLayout method on the viewcontroller's view (not the navigationControllers')
self.toolbarItems = toolButtons;
[self.view setNeedsLayout];
I would like to make an extra button in the iPhone keyboard left bottom corner like on the photo bellow. Is it possible to do this ?
the only way to customize those buttons is to rebuild the keyboard itself.
http://www.raywenderlich.com/1063/ipad-for-iphone-developers-101-custom-input-view-tutorial
Ray has always got some good tutorials on iphone dev. being able to customize your inputView is only half the battle tho. You will then need to build the custom view. Likely you will want to emulate the existing keypad, with your custom button obviously.
as a side note. to dismiss the keyboard you need to resignFirstResponder via the first responder.
When you get that far, here is the code I use to do exactly that
#implementation UIView (FindAndResignFirstResponder)
- (BOOL)findAndResignFirstResponder
{
UIView *responder = [self findFirstResponder];
if (responder) {
[responder resignFirstResponder];
return YES;
}
return NO;
}
- (UIView*)findFirstResponder
{
if (self.isFirstResponder) {
return self;
}
for (UIView *subView in self.subviews) {
UIView *responder = [subView findFirstResponder];
if (responder != nil)
return responder;
}
return nil;
}
#end
call the if you have a hold of the superview of all your inputs, you can call findAndResignFirstResponder on that view.
Or as you can see the findAndResignFirstResponder calls resignFirstResponder on the "found" firstResponder. therefore if you have the first responder you can just resign it
No it is not. The Keyboard is owned by the system. You can change the kind of keyboard (normal, numeric, twitter etc), but you can't customise it. It is a question which is worth a +1
I have a UITableView with a custom cell that has a TextField. I have the DecimalPad comes up, and as we all know, there is no done key. I previously had resolved this type of issue when I had a "Decimal only" textfield on a normal UIView by handling the TouchesEnded event and then checking to see if the TextField was the first responder and if so, it would then resign, but if that technique could work now then I'm not able to figure out who's TouchesEnded I should be using (The UIView that everything is presented on, the UITableView, the Cell, the CellControler, the TextField.. I think I've tried everything).
I'm hoping there's another, cleaner way of dealing with this.
Anyone?
I think David has the best idea - here is some Monotouch code to get you started. You will need to put this in the View Controller where the decimal pad is being shown:
UIView dismiss;
public override UIView InputAccessoryView
{
get
{
if (dismiss == null)
{
dismiss = new UIView(new RectangleF(0,0,320,27));
dismiss.BackgroundColor = UIColor.FromPatternImage(new UIImage("Images/accessoryBG.png"));
UIButton dismissBtn = new UIButton(new RectangleF(255, 2, 58, 23));
dismissBtn.SetBackgroundImage(new UIImage("Images/dismissKeyboard.png"), UIControlState.Normal);
dismissBtn.TouchDown += delegate {
textField.ResignFirstResponder();
};
dismiss.AddSubview(dismissBtn);
}
return dismiss;
}
}
If you're targeting iOS 4.0 or greater you can create an inputAccessoryView containing a Done button to attach to the keyboard that will dismiss the keyboard when tapped. Here is an example from the documentation on creating a simple inputAccessoryView.
You could dismiss it when the user taps on the background; I think that's the most intuitive way.
In Interface Builder, change your View's class to UIControl. This is a subclass of UIView, so your program will work the same way, but you also get the standard touch events.
From here it's simple, create a method for the Touch Down event:
[numberField resignFirstResponder]
Of course it might be slightly different with MonoTouch -- unfortunately I don't know much about it, but wanted to help.
Hopefully you can use the concept, and modify your code accordingly.
Or you may just add some gesture to your main view.
For example:
//Just initialise the gesture you want with action that dismisses your num pad
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
UISwipeGestureRecognizer *swipeToHideNumPad = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(hideNumPad:)];
swipeToHideNumPad.delegate = self;
swipeToHideNumPad.direction = UISwipeGestureRecognizerDirectionDown;
[swipeToHideNumPad setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:swipeToHideNumPad];
}
//action
- (void)hideNumPad:(UIGestureRecognizer *)gestureRecognizer
{
[self.amountTextField resignFirstResponder];
}
I have an iPhone application which is based on the "Window based application" template and which uses a main view with some embedded subviews.
For some action I need a confirmation by the user. Therefore, I create an UIActionSheet and ask the user for feedback.
The problem is, that the action sheet does not show at all. Instead, the screen gets darker. The sheet and the requested buttons do not show. After that, the application hangs. The darkening of the screen is a normal behavior as part of the animation which normally shows the action sheet.
Curiously, the same code works fine, if invoked in the viewDidLoad method. It does not work if invoked in the buttonPressed method which starts the action requiring the confirmation.
- (void) trashButtonPressed {
// This method is called in the button handler and (for testing
// purposes) in the viewDidLoad method.
NSLog( #"trashButtonPressed" );
UIActionSheet* actionSheet =
[[UIActionSheet alloc] initWithTitle: #"Test"
delegate: self
cancelButtonTitle: #"Cancel"
destructiveButtonTitle: #"Delete Sheet"
otherButtonTitles: nil];
[actionSheet showInView: self.view];
[actionSheet release];
}
- (void) willPresentActionSheet:(UIActionSheet *) actionSheet {
NSLog( #"willPresentActionSheet" );
}
- (void) didPresentActionSheet:(UIActionSheet *) actionSheet {
NSLog( #"didPresentActionSheet" );
}
- (void) actionSheet:(UIActionSheet *)actionSheet
didDismissWithButtonIndex:(NSInteger)buttonIndex {
NSLog( #"actionSheet:didDismissWithButtonIndex" );
}
As you can see, I have added some logging messages to the protocol handlers of the UIActionSheetDelegateProtocol. The "will present" and "did present" methods get called as expected, but the sheet does not show.
Does anybody know, what's wrong here?
I wonder if [actionSheet showInView: self.view]; is enough to have the actionSheet have itself retained by self.view. (edit: retain count jumps from 1 to 4 so not a problem here)
Have you checked the dimensions of your view? The sheet is positioned within the view, but if self.view would refer to a big scrollview, you might just have a sheet below the surface. In short, are you sure that self.view.frame and self.view.bounds have the same values in the two situations you are referring to? Is it the same view (when just NSLog(#"%x",self.view)-ing it's address)?
edit to clarify: do
NSLog(#"%f %f %f %f",
self.view.frame.origin.x,self.view.frame.origin.y,
self.view.frame.size.width,self.view.frame.size.height);
and please tell what you see on the console. I get your "screen just gets darker" if I set either a 0,0,0,0 frame or a 0,0,320,800 frame, so this might be it...
Actually, I think you've hit the same issues I've seen.
In iOS 8 & 9, the UIActionSheet does get displayed... oh... but behind the onscreen keyboard, so you can't see it. You just see the rest of the screen going darker.
This, apparently, is Apple's latest UI improvement idea, to keep the screen uncluttered. ;-)
The simple solution is to add one line of code before displaying your UIActionSheet:
[self.view endEditing:true];
This dismisses the onscreen keyboard, making your beautiful action sheet visible again.
Alternatively, I have documented here how to replace your UIActionSheet with UIAlertController.