UITextField Resigning Sporadically - objective-c

This is a really odd issue because I can't give much explanation here. I have UITextField within a UITableView cell. Pretty straightforward...
When I select my UITextField it occasionally just resigns, not allowing the user to interact with the keyboard at all. This happens completely randomly and I don't have the slightest clue why it's happening. Has this happened to anyone else?

If I correct understand, you need push up (resize) your view.
1) Make sure that your textfield's delegate set to viewconntroller. 2) implement methods
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[self resizeView:YES toPoint: -70]; // example
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[self resizeView:NO toPoint: 0];
}
when resizeView is:
-(void) resizeView:(BOOL)top toPoint:(int)point
{
if (top)
[UIView animateWithDuration:0.3 animations:^{
self.view.transform = CGAffineTransformMakeTranslation(0, point);
}];
else
{
[UIView animateWithDuration:0.3 animations:^{
self.view.transform = CGAffineTransformMakeTranslation(0, point);
}];
}
}
Also you may increase text field frame, may be randomnicity of resigning depend on touch handle by table cell cut not textfield. Try disable user interaction for table or separate cell if this possible to check it.

Would it happen when the cell scrolls offscreen, by any chance?

Related

Waiting for a UIView to finish

[_articleTxtView setFont:[UIFont systemFontOfSize:_fontSizeInt]];
[_articleTxtView layoutIfNeeded];
[_articleTxtView sizeToFit];
The above code is triggered with a press of a UIButton and responsible of changing the size of a UITextView. Every time the UIButton is pressed the _fontSizeInt changes to a bigger number and the UITextView height changes accordingly.
The problem is that layoutIfNeeded and sizeToFitare called before setFont is finished and cuts UITextView in the middle.
Possible solutions:
This solution works great but I'd preffer not using something with such a bad practice.
..
[_articleTxtView setFont:[UIFont systemFontOfSize:[DataManager sharedDataManager].fontSize]];
[self performSelector:#selector(test) withObject:nil afterDelay:0.01];
}
- (void)test
{
[_articleTxtView layoutIfNeeded];
[_articleTxtView sizeToFit];
}
I thought about using the next code but for some reason it doesn't always work. Also I'm not sure if that's a proper use of the animation block (there's really no animation involved):
[UIView animateWithDuration:0.4 animations:^()
{
[_articleTxtView setFont:[UIFont systemFontOfSize:[DataManager sharedDataManager].fontSize]];
}
completion:^(BOOL finished)
{
[_articleTxtView layoutIfNeeded];
[_articleTxtView sizeToFit];
}];
Is there a better way to let a method "know" when a UIView finished painting \ loading?
Thanks
You could implement viewDidLoad (called once) or viewWillAppear (called every time) in the articleTxtView view controller class

Alternative to "self" in calling methods in Objective-C

This may sound really noob, but i've spent an entire day wrestling with this problem and would appreciate some help.
You see i have a method which I call more than once inside gameplay. If I use [self myMethod]; then it works for ONE time. And then when I call it again, the animation in the method doesn't commence anymore.
What I need is to replace "self" with an alternative that can be "alloc'ed" and "released" to make my animations work.
I've tried;
#implementation gameViewController
gameViewController *object = [[gameViewController alloc] init];
[object myMethod];
However the above substitute for self doesn't even call on the method. I don't know what I did wrong, it's suppose to work just like "self".
Is there something i missed? How do you make an object of the class to work just like "self" does?
Thanks so much.
Here is a more detailed look of my code;
[self explosionAnimations];
- (void) explosionAnimations
{
UIImage *image = [UIImage imageNamed: #"Yellow Explosion.png"];
[bomb setImage:image];
[UIView beginAnimations:#"bomb1ExplosionIncrease" context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
bomb.transform = CGAffineTransformMakeScale(3.4, 3.4);
[UIView commitAnimations];
}
The setImage works fine every time. But the animations stop working on the second call of the method. While in the console it logs "animation completed" with nothing happening to the image.
This leads me to believe that somehow "self" believes that the animation was already done and will not bother to do it again. So I thought a new "alloc" might give it a kick awake.
The problem doesn't have anything to do with "self". The problem is that you set the transform in your animation, and then when you run it again, you're setting the same transform, so it does nothing. You need to reset the frame to the new frame and then set the transform back to the identity transform before you do the animation again. Also, you should be using block based animations. I'm not sure this is the best way to do it, but this worked for me (if you have auto layout turned off).
- (void)explosionAnimations {
UIImage *image = [UIImage imageNamed: #"Yellow Explosion.png"];
[self.bomb setImage:image];
[UIView animateWithDuration:.5 animations:^{
self.bomb.transform = CGAffineTransformMakeScale(3.4, 3.4);
} completion:^(BOOL finished) {
CGRect newFrame = self.bomb.frame;
self.bomb.transform = CGAffineTransformIdentity;
self.bomb.frame = newFrame;
}];
}
If you're doing this in an app with auto layout turned on (which it is by default), then I would not use a transform, but just resize the width and height of the image view by adjusting its height and width constraints. So, in this method, you should make IBOutlets to height and width constraints you make in IB, then change their constant values in an animation block:
[UIView animateWithDuration:.5 animations:^{
self.heightCon.constant = self.heightCon.constant * 3.4;
self.widthCon.constant = self.widthCon.constant * 3.4;
[self.view layoutIfNeeded];
}];

Can't interact with (some) UI elements in a ScrollView when the keyboard is displayed

I've got a fairly basic interface that normally looks like this:
Fairly uninspired, but that's what the spec says to build. In any case, part of the issue is that when the onscreen keyboard pops up, this happens:
Now that's not a big issue by itself; I've got everything inside of a UIScrollView, and am using the following code to handle the keyboard showing and hiding:
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = referrerInfoView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
newFrame.size.height -= (keyboardFrame.size.height - 71) * (up? 1 : -1);
referrerInfoView.frame = newFrame;
referrerInfoView.contentSize = CGSizeMake(703, 633);
//FIXME: doesn't play nice with rotation when the keyboard is displayed
if (up && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
UIView* focusedField = [referrerInfoView findFirstResponder];
if (focusedField && focusedField.frame.origin.y > 340.0) {
referrerInfoView.contentOffset = CGPointMake(0.0, focusedField.frame.origin.y - 200.0);
}
}
else {
referrerInfoView.contentOffset = CGPointMake(0.0, 0.0);
}
[UIView commitAnimations];
}
Not the most robust thing in the world, but it does well enough for now. That gets me to here:
Now that's fine, except none of the elements in the shaded boxes respond to user interaction while the keyboard remains onscreen. The UIScrollView responds to interaction, as do all the other controls in the view. But all the 'address' fields stop working.
Essentially it seems that all the controls that were being hidden behind the keyboard before I scrolled them back into view still think that they're being hidden behind the keyboard. Any ideas on how to fix this?
I found the solution to this. Basically the layout that I originally had was like this:
UIScrollView
UIView
<Components>
The container view inside of the scrollview wasn't strictly necessary, but it didn't seem like it should hurt anything either. That assumption, it turns out, was incorrect. Long story short, I changed the interface so that it is structured like this:
UIScrollView
<Components>
And that solved the problem. Can't say I really understand why, but hopefully this information will help the next person who happens to run into this issue.

Is there a recommended or even automatic way to move a UITextField into view when editing it?

Having implemented this now in various flavors, I wonder: if editing starts on a UITextField and the keyboard appears, is there a recommended or even automated way that would keep the textfield visible by scrolling it up?
I think it would be easiest and best to scroll up the whole root view. Is there something in the API I've been missing so far, that would save me from writing this code myself?
I sit all my UITextFields on a contentView (In my example I have called this view 'movableView') and then when the user taps one of the text fields
//The hardcoded 10's and 20's are the origin of the view before
//the user starts messing with it!
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
[self scrollViewToTextField:textField];
//Other stuff I want to do here
return YES;
}
- (void)scrollViewToTextField:(id)textField
{
UITextField* tf = (UITextField*)textField;
CGPoint newOffset = tf.frame.origin;
newOffset.x = 10;
newOffset.y = 20 - newOffset.y;
//This is a category method on UIView which simply adjusts the views
//frame over a delay.
[self.movableView moveToX:newOffset.x andY:newOffset.y withDuration:0.3f];
}
When the editing is finished you have to move the view back
-(void)textFieldDidEndEditing:(UITextField *)textField {
[self resetView];
// do other stuff here such as grab the text and stick it in ivars etc.
}
-(void)resetView {
[self.movableView moveToX:10.0f andY:10.0f withDuration:0.3f];
}
Just in case - here is the category method for completeness
// UIView+BasicAnimation.h
-(void) moveToX:(CGFloat) x andY:(CGFloat) y withDuration:(NSTimeInterval) duration;
// UIView+BasicAnimation.m
-(void) moveToX:(CGFloat) x andY:(CGFloat) y withDuration:(NSTimeInterval) duration {
CGRect newFrame = self.frame;
newFrame.origin.x = x;
newFrame.origin.y = y;
[UIView beginAnimations:#"BasicAnimation" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:duration];
self.frame = newFrame;
[UIView commitAnimations];
}
I don't think any such thing exists and it seems like an odd omission. When you consider the existence of iPad split keyboards, it seems even more like something that should be done correctly once and provided in the API.
For a current project, I'm trying out TPKeyboardAvoidingScrollView. (https://github.com/michaeltyson/TPKeyboardAvoiding)
It's common to implement this by using an UIScrollView and modifying the content offset when a field gains firstResponder status.

Getting a button to disappear when a text field is done editing, but switches to another text field

My UIButton is set to disappear every time my UITextField is done editing, I invoke the textFieldDidEndEditing: method, and just have the button fade away. This works fine, unless I switch to another textfield without clicking out of the first one. So for instance, I'm on textfield A, and just tap textfield B, the keyboard still stays up, and so does the button. I don't believe that there is a method that covers textfields switching like this, only when ALL the textfields are done editing. Am I wrong? Here is my code:
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField
{
negButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
negButton.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, 37, textField.frame.size.height);
[negButton setAlpha:0];
return YES;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
if ([textField isEditing])
{
[UIView animateWithDuration:0.3 animations:^
{
field = textField;
CGRect frame = textField.frame;
frame.size.width -= 40;
frame.origin.x += 40;
[negButton setAlpha:1];
[textField setFrame:frame];
[self.view addSubview:negButton];
}];
}
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
[UIView animateWithDuration:0.3 animations:^
{
CGRect frame = textField.frame;
frame.size.width += 40;
frame.origin.x -= 40;
[negButton setAlpha:0];
[textField setFrame:frame];
}
];
}
It sounds to me like you are invoking the button to appear on the
textFieldShouldBeginEditing
method, which is fine, and you are removing it on the
textFieldDidEndEditing
method, also fine. Why you are not seeing the button disappear when you switch to another text box is because when you tap that text box, the shouldBeginEditing method is called immediately after the endEditing method, resulting in the button reappearing immediately after it is deleted.
This is the way it is supposed to work, and if you want it to work a different way, you will have to make the code specific to each text field
EX:
- (BOOL)textFieldShouldBeginEditing:(UITextField*)textField
{
if(textField == myField1)
{
//make button appear
}
else if(textField == myField2)
{
//Something else
}
}
Voila!
The problem here is the order that your delegate methods are being called.
Let's say that you are going from textField1 to textField2.
Once textField1 is already active and you click on textField2, they get called like this:
textFieldShouldBeginEditing (textField2)
textFieldShouldEndEditing (textField1)
textFieldDidEndEditing (textField1)
textFieldDidBeginEditing (textField2)
You are creating your new negButton in textFieldShouldBeginEditing which over-writes the reference to the "old" button (beside textField1) by creating one beside textField2 and storing it's reference instead. Next, you call textFieldDidEndEditing and textFieldDidBeginEditing on the new button.
What you want to do is move your code that is currently in textFieldShouldBeginEditing to the beginning of textFieldDidBeginEditing so that the previous two methods act upon the appropriate button before the new one is created.