Silver Challenge


#1

I found several options for dismissing a number pad (including adding a “done” button in the bottom left corner), but this was simplest one. In DetailViewController.m, add:

[code]// Use this code to dismiss a Number Pad when the user touches the background

  • (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
    [valueField resignFirstResponder];
    }[/code]

#2

Found several “solutions” which didn’t work for me, but yours did, so thanks for that :slight_smile:

Removed my bonus as it’s implemented later in the next chapter :slight_smile:


#3

HI, I’ve just done the silver challenge, challenge is the keyword!

I looked at the trick of putting a button on top of the keyboard and found myself thinking it was a messy solution.
I then looked at the InputAccessoryView and InputView protocols and did an implelnetation of inputAccessoryView, which worked ok but i didn’t really like the aesthetic of it for this purpose.
In the end I went with tapping the background to dismiss the keyboard.

Whilst doing this I was left wondering why Apple haven’t implemented the done button option on the Decimal Keypad which as far as I can see you can only access programmatically?! I do think I can understand why they haven’t given us the option on the numeric keypad however.

David :slight_smile:


#4

Yeah. When I got to the next chapter I was happy to see I had found the same answer, but a bit silly for my post. :slight_smile:

I’ll second the “why didn’t Apple add a Done button” question. My theory is that, on the text keyboard, the Backspace and Done buttons are on the right side. This is not possible with the numerical keyboard, so it would hinder your muscle memory if the Done button is on different sides of the keyboard depending on the type of input. That’s actually one of the reasons I didn’t want to implement the Done button and kept looking for a simpler solution.


#5

My approach was to create a ‘Done’ button on the UINavigationBar when the user began editing.

First step: Declare two methods in DetailViewController.h

[code]- (IBAction)createDoneButton:(id)sender;

  • (void)doneEditingValueField[/code]

Second step: Add corresponding implementation to DetailViewController.m

- (IBAction)createDoneButton:(id)sender { UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonItemStylePlain target:self action:@selector(doneEditingValueField)]; [[self navigationItem] setRightBarButtonItem:doneButton]; }

- (void)doneEditingValueField { [valueField resignFirstResponder]; [[self navigationItem] setRightBarButtonItem:nil]; }

The final step was to make connections in the XIB file.
[1] Open DetailViewController.xib and control+click on ‘File Owner.’ A popup will appear.
[2] Drag from ‘createDoneButton’ onto the text field. Another popup will appear.
[3] Click ‘editing did begin.’

I hope that helps!


#6

I also added a Done button to the UINavigationBar that appears when the Value field is being edited, but I implemented it in UITextFieldDelegate protocol methods in DetailViewController.m rather than with the IB:

[code]- (BOOL)textFieldDidBeginEditing:(UITextField *)textField
{
if (textField == valueField) {
UIBarButtonItem *doneEditingButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(doneEditingValueField:)];
[[self navigationItem] setRightBarButtonItem:doneEditingButton];
}
return YES;
}

  • (void)doneEditingValueField:(id)sender
    {
    [valueField resignFirstResponder];
    }

  • (BOOL)textFieldDidEndEditing:(UITextField *)textField
    {
    if (textField == valueField) {
    [[self navigationItem] setRightBarButtonItem:nil];
    }
    return YES;
    }
    [/code]


#7

Great implementation !

I have one question, though :
If I use your code, it works perfectly :

- (void)doneEditingValueField:(id)sender { [valueField resignFirstResponder]; }

I tried before to define the method this way :

- (void)doneEditingValueField:(UITextField *)myValueField { [myValueField resignFirstResponder]; }
and … it didn’t work : compiled OK, but returned an error at runtime :

Could someone explain me why ?
I thought the input data of this method was UITextfield, so what’s wrong ??


#8

The argument passed to doneEditingValueField: when the Done button is pressed is a pointer to the UIBarButtonItem from which the button was created, not a UITextField *. Note that in the working implementation, this value is not used for anything.

You’re right that it is the UITextField * to which you need to send the resignFirstResponder message, but you can do that by sending it to the IBOutlet ivar called valueField that the Value text field was hooked up to.


#9

The solution to Silver has a lot of good implementations, but I liked the touching the background one the best. What I added, though, was this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [valueField resignFirstResponder];
    [serialNumberField resignFirstResponder]; //Added for serial number
    [nameField resignFirstResponder]; // Added for name 
}

I wanted the user experience to be the same and predictable no matter which field they were editing.

Great book, huh? I’m really enjoying it.


#10

[quote=“drabenau”]The solution to Silver has a lot of good implementations, but I liked the touching the background one the best. What I added, though, was this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [valueField resignFirstResponder];
    [serialNumberField resignFirstResponder]; //Added for serial number
    [nameField resignFirstResponder]; // Added for name 
}

I wanted the user experience to be the same and predictable no matter which field they were editing.

Great book, huh? I’m really enjoying it.[/quote]

Great book, indeed. Thanks for the elegant method - works great!


#11

[quote=“drabenau”]The solution to Silver has a lot of good implementations, but I liked the touching the background one the best. What I added, though, was this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [valueField resignFirstResponder];
    [serialNumberField resignFirstResponder]; //Added for serial number
    [nameField resignFirstResponder]; // Added for name 
}

I wanted the user experience to be the same and predictable no matter which field they were editing.[/quote]

I like this solution but I think it can be simplified even more:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self view] endEditing:YES];
}

Each field will behave in the same manner and you don’t have to worry about updating this if you add or remove a field.


#12

I didn’t see this mentioned above but:

- (BOOL)textFieldShouldReturn:(UITextField *)textField { // Allow's the return key on the keyboard to resign the keyboard as first responder. [textField resignFirstResponder]; return NO; }

Is an easy way to allow the return key to resign the keyboard alongside the code for touching off screen.


#13

My solution that adds toolbar in NumberPad accessory view:

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    if (textField == valueField) {
        UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
        numberToolbar.barStyle = UIBarStyleBlackTranslucent;
        numberToolbar.items = [NSArray arrayWithObjects: [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], 
                               [[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
                               nil];
        [numberToolbar sizeToFit];
        valueField.inputAccessoryView = numberToolbar;
    }
}
-(void)doneWithNumberPad{
    [valueField resignFirstResponder];
}

#14

I did two things. First one is using the fact that our UITextFields have delegate, so I did this

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
	[textField resignFirstResponder];
	return YES;
}

which actually dimisses the keyboard for all 3 text fields on pressing Return.

The second thing I did is a transparent button for DetailedViewController.xib, which I scaled for the whole area and put behind the others.
Then, on clicking anywhere outside the text fields I implemented the IBAction

- (IBAction)dismissKeyboard:(id)sender {
	[nameField resignFirstResponder];
	[serialNumberField resignFirstResponder];
	[valueField resignFirstResponder];
}

#15

I thought it would be cool to swipe down the keyboard. This is my first time taking a swing at swiping - please let me know if I’m violating any ‘best-practice’ rules (Ya I know RTFM, but jumping ahead in the book, hate spoilers).

[code]-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
_aTouch = [touches anyObject];
startTouchPosition = [_aTouch locationInView:[self view]];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
endPoint = [_aTouch previousLocationInView:[self view]];
CGFloat yaxis = 12.0;
CGFloat ytravel = endPoint.y - startTouchPosition.y;
if (ytravel > yaxis){
[[self view] endEditing:YES];}
}[/code]


#16

Hi guys,
just thought I’d offer my solution to dismissing the numeric keyboard

In DetailViewController.h, I added the UITextFieldDelegate protocol

@interface DetailViewController : UIViewController
{
_weak …
}

Then in DetailViewController.m, I set the delegate for the value text field in the - (void) viewDidLoad method

  • (void) viewDidLoad {
    [super viewDidLoad];
    [[self view] setBackgroundColor:[UIColor groupTableViewBackgroundColor]];

    valueField.delegate = self;
    }

and then finally, implemented the delegate method - (BOOL)textFieldShouldReturn:(UITextField *)textField

  • (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
    }

I hope this helps.

Cheers


#17

i solved this using the following:-
In DetailViewController.m

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    if (textField==valueField) {
        [textField resignFirstResponder];
        return YES;
    }
    return NO;
}

Is this good enough? Out of curiosity, if i returned NO inside the if clause, this still would have worked as long as resignFirstResponder message is there in place. So whats the difference in functionally when i return YES and when i return NO. I read thru the docs, they say returning YES causes the textFieldShouldReturn: to implement the default behavior. What is the default behavior of this method?

For the first two fields i.e. nameField and serialNumberField, I want the keypad control to move from the current field to the next immediate one once the typing is done. Any ideas on how to do that?


#18

Why would you use this in the code. Hadn’t you done this already in the XIB file while making connections? I mean from valueField to File’s owner i.e. DetailViewController. If you hadn’t then its understandable.


#19

Another solution is to override a touch event for the detail view.


    override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
        view.endEditing(true)

    }

By doing so you don’t need to ask each ui widget to resignFirstResponder