I do some practice with iPhone4S about UITextField on iOS 7.1.2.
Interface:
The interface of the first version is simple, which just has a custom UITextField named MyUITextField and a UIButtom object that use to cancel the search operation. Inside the textField, its leftView property is initially set to a UIButton object, which background image is a magnifying glass. When users tap in the textField, that magnifying glass button will be removed and the leftView property will also set to a new UIButton object, which background image is a inverted triangle. When users tap the triangle button, app will create a new view object.
Main code:
//In this version,the textField's original frame property is set to (10,40,250,30)
//and the main operations are like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.myTextField.delegate = self;
self.myTextField.leftViewMode = UITextFieldViewModeUnlessEditing;
self.myTextField.leftView = [self creCustomSearchBar];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyBoardWillAppear:)
name:#"UIKeyboardWillShowNotification"
object:nil];
[self.cancleSearchButton addTarget:self
action:#selector(cancleSearch:)
forControlEvents:UIControlEventTouchUpInside];
}
/*when tapping in the textField,keyboard will appear*/
- (void)keyBoardWillAppear:(NSNotification *)notification
{
CGRect newLeftViewIndicatorRect = CGRectMake(20,5,20,20);
UIButton *newLeftViewIndicator = [[UIButton alloc] initWithFrame:newLeftViewIndicatorRect];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"searchbar_textfield_down_icon#2x" ofType:#"png"];
[newLeftViewIndicator setBackgroundImage:[UIImage imageWithContentsOfFile:imagePath] forState:UIControlStateNormal];
[newLeftViewIndicator addTarget:self action:#selector(createActuralLeftView:) forControlEvents:UIControlEventTouchUpInside];
self.myTextField.leftView = newLeftViewIndicator;
/*in the second verson need to call */
//[self adjustViewFrame];
[self.cancleSearchButton setTitle:#"取消" forState:UIControlStateNormal];
}
- (void)createActuralLeftView:(UIButton *)leftViewButton
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapRegionAboveKeyboard:)];
[self.view addGestureRecognizer:tapGesture];
NewLeftView *leftView = [[NewLeftView alloc] initWithFrame:CGRectMake(10, 80, 140, 100)];
leftView.delegate = self;
[self.view addSubview:leftView];
}
- (void)tapRegionAboveKeyboard:(UITapGestureRecognizer *)tapGesture
{
for (UIView *v in self.view.subviews) {
if ([v isKindOfClass:[NewLeftView class]]) {
[v removeFromSuperview];
[self.view removeGestureRecognizer:tapGesture];
return;
}
}
}
//in the second version need to call
- (void)adjustViewFrame
{
[[self.myTextField class] animateWithDuration:0.05 animations:^{
[self.myTextField setFrame:CGRectMake(self.myTextField.frame.origin.x, 40, self.myTextField.frame.size.width, self.myTextField.frame.size.height)];
}];
[[self.cancleSearchButton class] animateWithDuration:0.05 animations:^{
[self.cancleSearchButton setFrame:CGRectMake(self.cancleSearchButton.frame.origin.x, 40, self.cancleSearchButton.frame.size.width, self.cancleSearchButton.bounds.size.height)];
}];
}
In the first version things work well.
But in the second version, I set the textField frame property to (10,260,250,30), so I need to call the adjustViewFrame method in the keyBoardWillAppear: to reposition the textField in case of obscuring by the keyboard.
Here comes the problem: the textField's position is correctly moved to the right place, but when I tap the inverted triangle button, the textField disappeared.
I can't figure out what's going wrong here.
Related
I have added a button to my annotation view, and it appears correctly. When the button is tapped, I want a call to be made, but when I tap the button, it doesn't respond (the button doesn't even highlight). It seems that the button doesn't receive the touch event, but I don't know why.
Here is my code in customAnnotationView.m
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
NSLog(#"initWithAnnotation start");
//initialze the view
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
CGRect frame = self.frame;
frame.size = CGSizeMake(60.0, 85.0);
self.frame = frame;
self.backgroundColor = [UIColor clearColor];
self.centerOffset = CGPointMake(30.0, 42.0);
}
//this has nothing to do with my question
self.title=[[[NSString alloc] init] autorelease];
self.description=[[[NSString alloc] init] autorelease];
self.phoneNumber=[[[NSString alloc] init] autorelease];
customAnnotation * tempCust = (customAnnotation *)annotation;
self.title=annotation.title;
self.description=tempCust.description;
self.phoneNumber=tempCust.phoneNumber;
//here is the question button
self.userInteractionEnabled=YES;
self.exclusiveTouch=NO;
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Call" forState:UIControlStateNormal];
//decide the button's position
CGRect rect=button.frame;
rect.origin.x=15;
rect.origin.y=47;
rect.size.width=40;
rect.size.height=20;
button.frame=rect;
[self addSubview:button];
[button becomeFirstResponder];
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
NSLog(#"initWithAnnotation finished");
return self;
}
//action method
-(void)buttonClicked:(id)sender{
NSString *callNumber=[[[NSString alloc] initWithFormat:#"tel://%#",self.phoneNumber] autorelease];
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:callNumber]];
}
Why doesn't the button work?
self.rightCalloutAccessoryView = button;
Use the above instead of [self addSubview:button];
Hope this help's you
I have a Button that when I press it, it does not fire the target selector that I've added. I've made the button Different Images, so I can see that I am Pressing it.
So here is the Funny if I Press, and drag outside of the button, but not outside of the button's immediate superView, the target selector is fired!
I've also in testing set the setClipsToBounds:YES on all the super/sub views just to be sure it was still in the views bounds. Seems to be within bounds. The dragging outside the button area seems to be omni directional, so its not like I can only tap/drag right. Left up and down work too. I can tap, drag out then back in and it works. If I don't start to drag and just tap and hold, the button highlights and then goes back to unselected state.
Here is the code for the Button. The Button is on a UIView along with a UITextView, Actually onTop Of the UITextView. The UIView that all of this is on is on a Larger View, which is on a Scaling/Scrolling view
messageLookupButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 21, 20)];
[messageLookupButton setTitle:#"junk" forState:UIControlStateNormal];
[messageLookupButton sizeToFit];
[messageLookupButton setTag:kGearButtonView];
//Get the images for the buttons
UIImage *gearButtonImage = [UIImage imageNamed:#"gear.png"];
UIImage *gearButtonImage2 = [UIImage imageNamed:#"StatusLightOn.png"];
[messageLookupButton setImage:gearButtonImage forState:UIControlStateNormal];
[messageLookupButton setImage:gearButtonImage2 forState:UIControlStateHighlighted];
[messageLookupButton addTarget:self action:#selector(gearPressed:) forControlEvents:UIControlEventTouchUpInside];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(processLookupResults:)
name:kRefreshFromPopover object:nil];
[self addSubview: messageLookupButton ];
[messageLookupButton release];
[messageLookupButton setCenter:CGPointMake(CGRectGetMaxX(elementViewContents.bounds) -kElementContentFrameOffset -(CGRectGetWidth( messageLookupButton.bounds)/2), CGRectGetMidY(elementViewContents.bounds))];
[self bringSubviewToFront:messageLookupButton];
The Scroll View has several gesture recognizers on it. Though they don't seem to interfere with other buttons and controls that I've put on the screen. Though I have a feeling its the Scroll View that is the problem.
scroll view code clip:
[scrollContentView setUserInteractionEnabled:YES];
[scrollContentView setExclusiveTouch:YES];
[scrollContentView setCanCancelContentTouches:YES];
[scrollContentView setDelaysContentTouches:YES];
I ended up Just adding the gear as an Image to the View, then created a invisible button that was the same size as the UIView that I placed the gear icon on.
-(void) addMessageLookupSelector {
// Set a default Color if there is none
if (_isMessageLookupField ){
// Add Gear to End Of Text Field
if (!messageLookupImageView) {
messageLookupImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 21, 20)];
[messageLookupImageView setTag:kGearButtonView];
[messageLookupImageView setImage:[UIImage imageNamed:#"gear.png"] ];
[self addSubview: messageLookupImageView ];
[messageLookupImageView release];
}
[self positionMessageLookupImageView ];
}
[self setNeedsDisplay];
}
- (void)makeControlEditable {
//Setup the TextField so we can edit its value, need to see if there is a Write Animation Assocated with Element
[self setTheWriteTag];
if (writeTag) {
writeInputRequestedButton = [UIButton buttonWithType:UIButtonTypeCustom];
[writeInputRequestedButton setFrame:elementViewContents.frame];
[writeInputRequestedButton setUserInteractionEnabled:YES];
[writeInputRequestedButton setEnabled:YES];
// [writeInputRequestedButton setBackgroundColor:[UIColor clearColor]];
[self addSubview: writeInputRequestedButton];
[self bringSubviewToFront:writeInputRequestedButton];
[writeInputRequestedButton addTarget:self action:#selector(wantsToEditValue:) forControlEvents:UIControlEventTouchUpInside];
}
}
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];
}
}
My code:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect rectFake = CGRectZero;
UITextField *fakeField = [[UITextField alloc] initWithFrame:rectFake];
[self.view addSubview:fakeField];
UIView *av = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 39.0)];
av.backgroundColor = [UIColor darkGrayColor];
CGRect rect = CGRectMake(200.0, 4.0, 400.0, 31.0);
UITextField *textField = [[UITextField alloc] initWithFrame:rect];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:24.0];
textField.delegate = self;
[av addSubview:textField];
fakeField.inputAccessoryView = av;
[fakeField becomeFirstResponder];
}
I tried to add
[textField becomeFirstResponder]
at the end, but it does no work.
Another problem that delegate method to hide keyboard when ENTER is pressed does not work also.
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
I was facing the same challenge. Your (and my initial) approach probably don't work because the text field in the inputAccessoryView refuses to become first responder as the UITextField is not located on your screen initially.
My solution: check when the keyboard (and with that the accessory view) appear!
Step 1) Listen for the notification (make sure this code is executed before you want to receive the notification).
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(changeFirstResponder)
name:UIKeyboardDidShowNotification
object:nil];
Step 2) When the keyboard has appeared, you can set the textfield in your inputAccessoryView to become first responder:
-(void)changeFirstResponder
{
[textField becomeFirstResponder]; // will return YES;
}
I'm trying to use this to add button to toolbar:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setToolbarHidden:NO animated:NO];
self.navigationController.toolbar.translucent = YES;
self.navigationController.toolbar.barStyle = UIBarStyleBlack;
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(0.0, 0.0, 10.0, 10.0);
UIBarButtonItem *infoButton = [[UIBarButtonItem alloc] initWithCustomView:button];
NSMutableArray *a = [NSMutableArray arrayWithObject:infoButton];
[self.navigationController setToolbarItems:a];
}
But there is no button in toolbar when I started application! :(
Instead of setting the navigation controllers toolBarItems property try setting it in the currently displayed view controller like so:
[self setToolbarItems:[NSArray arrayWithObjects:infoButton, nil]];
Also adding infoButton to the toolBarItems will automatically retain it. So remember to place
[infoButton release];
at the bottom of your viewWillAppear method.