动画 UITextField 时的奇怪行为

发布于 2024-12-15 10:05:09 字数 3064 浏览 4 评论 0原文

我正在尝试为 UITextField 设置动画,但遇到了一个恼人且奇怪的问题。我的动画具有以下序列:

first state

在第一个状态中,应用程序具有 UITextField,相机 UIButton 和相机按钮后的取消 UIButton 未显示,因为它的位置超出了应用程序的限制。实际上我的应用程序的宽度为 320,取消按钮原点为 (350,7)

second state

在第二状态下,当用户触摸 UITextField,相机按钮 Alpha 通道设置为 0,取消按钮的原点设置为 (247,7)。

final state

最终状态与用户触摸键盘返回按钮或取消按钮后的第一个状态相同。

在处理过程中,UITextField 宽度和 x 轴上的取消按钮原点会进行动画处理。

我的代码是:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
  barcodeSearchButton.userInteractionEnabled = NO;
  cancelButton.userInteractionEnabled = NO;

   CGFloat cancelButtonXOffset = CGRectGetMaxX(barcodeSearchButton.frame) - cancelButton.frame.size.width;
   CGFloat searchFieldWidth = searchField.frame.size.width - cancelButton.frame.size.width + barcodeSearchButton.frame.size.width;
   [UIView animateWithDuration:0.3
         animations:^{
             searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldWidth, searchField.frame.size.height);
             cancelButton.alpha = 1.0;                
             cancelButton.frame = CGRectMake(cancelButtonXOffset, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);

             barcodeSearchButton.alpha = 0.0;

         }
         completion:^(BOOL finished) {
             barcodeSearchButton.userInteractionEnabled = NO;
             cancelButton.userInteractionEnabled = YES;
         }];    
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
  barcodeSearchButton.userInteractionEnabled = NO;
  cancelButton.userInteractionEnabled = NO;

  [UIView animateWithDuration:0.3
                 animations:^{
                     searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldStartWidth, searchField.frame.size.height);
                     cancelButton.alpha = 0.0;
                     cancelButton.frame = CGRectMake(cancelButtonStartX, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);
                     barcodeSearchButton.alpha = 1.0;                
                 }
                 completion:^(BOOL finished) {
                     barcodeSearchButton.userInteractionEnabled = YES;
                     cancelButton.userInteractionEnabled = NO;
                 }];        
}

当动画第一次执行到最终状态时,这意味着用户触摸 UITextField,写下(这部分很重要)字段上的一些文本,然后用户触摸键盘返回按钮出现问题。问题是,当 UITextField 的宽度也进行动画处理时,UITextField 中键入的文本也会进行动画处理。

动画的行为如下:

  1. UITextField 拉伸回其初始值。
  2. 取消按钮返回到其初始原点
  3. 相机按钮设置为 1.0
  4. 输入的文本从 UITextField 的左上角飞出,落在 UITextfield 中应有的位置还没走。

问题是步骤 4 不应该发生,而且问题是它只发生一次。如果再次启动该过程(触摸 uitextfield,输入一些文本,触摸返回键),则第 4 步不会发生。

我花了一天的时间试图解决这个问题,但没有成功。

I'm trying to animate a UITextField but I've been caught by a annoying and strange problem. My animation has the following sequence:

first state

In first state the application has the UITextField, the camera UIButton and the cancel UIButton after the camera button that is not been showed because it is been positioned out of the limits of the application. Actually my application has 320 of width and the cancel button origin is (350,7)

second state

In second state, when user touches on UITextField, the camera button alpha channel is set to 0 and the origin of cancel button is set to (247,7).

final state

The final state is the same as first state after user touched on Return button of keyboard or in cancel button.

During process the UITextField width and the cancel button origin in x axis are animated.

My code is:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
  barcodeSearchButton.userInteractionEnabled = NO;
  cancelButton.userInteractionEnabled = NO;

   CGFloat cancelButtonXOffset = CGRectGetMaxX(barcodeSearchButton.frame) - cancelButton.frame.size.width;
   CGFloat searchFieldWidth = searchField.frame.size.width - cancelButton.frame.size.width + barcodeSearchButton.frame.size.width;
   [UIView animateWithDuration:0.3
         animations:^{
             searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldWidth, searchField.frame.size.height);
             cancelButton.alpha = 1.0;                
             cancelButton.frame = CGRectMake(cancelButtonXOffset, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);

             barcodeSearchButton.alpha = 0.0;

         }
         completion:^(BOOL finished) {
             barcodeSearchButton.userInteractionEnabled = NO;
             cancelButton.userInteractionEnabled = YES;
         }];    
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
  barcodeSearchButton.userInteractionEnabled = NO;
  cancelButton.userInteractionEnabled = NO;

  [UIView animateWithDuration:0.3
                 animations:^{
                     searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldStartWidth, searchField.frame.size.height);
                     cancelButton.alpha = 0.0;
                     cancelButton.frame = CGRectMake(cancelButtonStartX, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);
                     barcodeSearchButton.alpha = 1.0;                
                 }
                 completion:^(BOOL finished) {
                     barcodeSearchButton.userInteractionEnabled = YES;
                     cancelButton.userInteractionEnabled = NO;
                 }];        
}

When the animation is executed until the final state ONLY for the first time, which means, user touched on UITextField, WROTE DOWN (this part is important) some text on field and after that the user touched on keyboard return button the problem appears. The problem is that the typed text in UITextField is animated when the width of UITextField is animated too.

The animation behaves like bellow:

  1. The UITextField stretches back to its initial value.
  2. Cancel button backs to its initial origin
  3. Camera button is set to 1.0
  4. The typed text flies from the top-left corner of UITextField and it lands into UITextfield to the position the it should not have gone.

The problem is that the step 4 should not happen and the problem is it happens only one time. If a start the process again (touch on uitextfield, type some text, touch on return key) the step 4 does not happen.

I spend a day long trying to solve this problem but I was unsuccessful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

伴我老 2024-12-22 10:05:09

感谢大家的回答,但我前段时间已经找到了解决方案。根据键盘状态,在 UITextField 中启动动画的正确方法是重写方法 textFieldShouldBeginEditingtextFieldShouldEndEditing

我的第一次尝试是重写 textFieldDidBeginEditingtextFieldDidEndEditing 来创建动画。我不知道动画在 textFieldShouldBeginEditingtextFieldShouldEndEditing 中工作但在 textFieldDidBeginEditingtextFieldDidEndEditing 中工作的原因。但它确实有效。

我修改后的代码版本:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {

    CGFloat cancelButtonXOffset = CGRectGetMaxX(barcodeSearchButton.frame) -    cancelButton.frame.size.width;
    CGFloat searchFieldWidth = searchField.frame.size.width - cancelButton.frame.size.width + barcodeSearchButton.frame.size.width;
    [UIView animateWithDuration:0.3
         animations:^{
             searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldWidth, searchField.frame.size.height);
             cancelButton.alpha = 1.0;                
             cancelButton.frame = CGRectMake(cancelButtonXOffset, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);

             barcodeSearchButton.alpha = 0.0;

         } completion:^(BOOL finished) {
             searchField.clearButtonMode = UITextFieldViewModeAlways;
         }]; 
    return YES;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    [UIView animateWithDuration:0.3
         animations:^{
             searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldStartWidth, searchField.frame.size.height);
             cancelButton.alpha = 0.0;
             cancelButton.frame = CGRectMake(cancelButtonStartX, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);
             barcodeSearchButton.alpha = 1.0;                
         } completion:^(BOOL finished) {
             searchField.clearButtonMode = UITextFieldViewModeNever;
         }];
   return YES;
}

Thanks for answers of everyone but I've found the solution some time ago. The correct way to start an animation in a UITextField, depending on the keyboard state, is overriding the methods textFieldShouldBeginEditing and textFieldShouldEndEditing.

My first attempt I was overriding textFieldDidBeginEditing and textFieldDidEndEditing to create the animations. I don't know the reason to the animations work in textFieldShouldBeginEditing and textFieldShouldEndEditing but not in textFieldDidBeginEditing and textFieldDidEndEditing. But it just works.

My revised code version:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {

    CGFloat cancelButtonXOffset = CGRectGetMaxX(barcodeSearchButton.frame) -    cancelButton.frame.size.width;
    CGFloat searchFieldWidth = searchField.frame.size.width - cancelButton.frame.size.width + barcodeSearchButton.frame.size.width;
    [UIView animateWithDuration:0.3
         animations:^{
             searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldWidth, searchField.frame.size.height);
             cancelButton.alpha = 1.0;                
             cancelButton.frame = CGRectMake(cancelButtonXOffset, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);

             barcodeSearchButton.alpha = 0.0;

         } completion:^(BOOL finished) {
             searchField.clearButtonMode = UITextFieldViewModeAlways;
         }]; 
    return YES;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    [UIView animateWithDuration:0.3
         animations:^{
             searchField.frame = CGRectMake(searchField.frame.origin.x, searchField.frame.origin.y, searchFieldStartWidth, searchField.frame.size.height);
             cancelButton.alpha = 0.0;
             cancelButton.frame = CGRectMake(cancelButtonStartX, cancelButton.frame.origin.y, cancelButton.frame.size.width,cancelButton.frame.size.height);
             barcodeSearchButton.alpha = 1.0;                
         } completion:^(BOOL finished) {
             searchField.clearButtonMode = UITextFieldViewModeNever;
         }];
   return YES;
}
满身野味 2024-12-22 10:05:09

在搜索字段上设置一些占位符文本,
_searchField.text = @"placeholder"

并设置
_searchField.clearsOnBeginEditing = YES;

或者,如果该值等于占位符文本,则可以清除该值
在 textDidBeginEditing 上

Set some placeholder text on the search field,
_searchField.text = @"placeholder"

and also set
_searchField.clearsOnBeginEditing = YES;

Or you can just clear out the value if it's equal to your placeholder text
on textDidBeginEditing

剩一世无双 2024-12-22 10:05:09

{编辑以改进修复}
我有这个完全相同的问题,还有一些进一步的细节以及一个确实为我解决了这个问题的小技巧。

所以首先是进一步的细节:

  1. 问题仅在帧动画第一次展开时发生
    UITextField 并且在该字段中输入了文本。如果
    UITextField 再次编辑,同样的动画再次发生,
    问题不会发生。
  2. searchField.clearsOnBeginEditing = YES; 没有清除问题。
  3. 问题出现期间我一直在使用占位符文本
    被观察到。它对结果没有影响。
  4. 更改 1 帧的文本属性确实可以解决问题。

这是我正在做的修复它的方法:

在我的 viewDidLoad 中,我将文本属性设置为单个空格,然后将一次分配分派给一个空字符串。

-(void)viewDidLoad {
    searchField.text = @" ";
    dispatch_async(dispatch_get_main_queue(), ^{
        searchField.text = @"";
    });
}

然后,在缩小和展开 UITextField 以及在屏幕上移动取消按钮的方法中,我检查这是否是瞬时动画并将持续时间设置为 0.0f。

- (void)showCancelButton {
    NSTimeInterval duration = 0.3f;

    [UIView animateWithDuration:duration animations:^{ 
        CGPoint buttonOrigin = cancelButton.frame.origin;
        CGSize buttonSize = cancelButton.frame.size;
        CGFloat buttonTravelDist = buttonSize.width + 10.0f;
        CGPoint onscreenPos = CGPointMake(buttonOrigin.x - buttonTravelDist, buttonOrigin.y);

        cancelButton.frame = CGRectMake(onscreenPos.x, onscreenPos.y, buttonSize.width, buttonSize.height);

        CGPoint fieldOrigin = searchField.frame.origin;
        CGSize fieldSize = searchField.frame.size;

        searchField.frame = CGRectMake(fieldOrigin.x, fieldOrigin.y, fieldSize.width - buttonTravelDist, fieldSize.height);
    }];
}

- (void)hideCancelButton {
    NSTimeInterval duration = 0.3f;

    [UIView animateWithDuration:duration animations:^{ 
        CGPoint buttonOrigin = cancelButton.frame.origin;
        CGSize buttonSize = cancelButton.frame.size;
        CGFloat buttonTravelDist = buttonSize.width + 10.0f;
        CGPoint onscreenPos = CGPointMake(buttonOrigin.x + buttonTravelDist, buttonOrigin.y);

        cancelButton.frame = CGRectMake(onscreenPos.x, onscreenPos.y, buttonSize.width, buttonSize.height);

        CGPoint fieldOrigin = searchField.frame.origin;
        CGSize fieldSize = searchField.frame.size;

        searchField.frame = CGRectMake(fieldOrigin.x, fieldOrigin.y, fieldSize.width + buttonTravelDist, fieldSize.height);
    }];
}

这已经彻底解决了我的情况。

{edited to improve the fix}
I have this exact same problem, and some further details as well as a small hack that is indeed fixing it for me.

So first the further details:

  1. The problem only occurs the first time the frame animation expands
    the UITextField and there is entered text in the field. If the
    UITextField is edited again, and the same animations happen again,
    the problem does not happen.
  2. searchField.clearsOnBeginEditing = YES; does not clear the problem.
  3. I've been using placeholder text the entire time the problem has
    been observed. It has no effect on the results.
  4. Changing the text property for 1 frame does have the effect of clearing the problem.

Here is what I am doing to fix it:

In my viewDidLoad I am setting the text property to a single space, then dispatching once an assignment to an empty string.

-(void)viewDidLoad {
    searchField.text = @" ";
    dispatch_async(dispatch_get_main_queue(), ^{
        searchField.text = @"";
    });
}

Then in my methods that shrink and expand the UITextField, as well as move a cancel button on-screen, I check if this is an instantaneous animation and set the duration to 0.0f.

- (void)showCancelButton {
    NSTimeInterval duration = 0.3f;

    [UIView animateWithDuration:duration animations:^{ 
        CGPoint buttonOrigin = cancelButton.frame.origin;
        CGSize buttonSize = cancelButton.frame.size;
        CGFloat buttonTravelDist = buttonSize.width + 10.0f;
        CGPoint onscreenPos = CGPointMake(buttonOrigin.x - buttonTravelDist, buttonOrigin.y);

        cancelButton.frame = CGRectMake(onscreenPos.x, onscreenPos.y, buttonSize.width, buttonSize.height);

        CGPoint fieldOrigin = searchField.frame.origin;
        CGSize fieldSize = searchField.frame.size;

        searchField.frame = CGRectMake(fieldOrigin.x, fieldOrigin.y, fieldSize.width - buttonTravelDist, fieldSize.height);
    }];
}

- (void)hideCancelButton {
    NSTimeInterval duration = 0.3f;

    [UIView animateWithDuration:duration animations:^{ 
        CGPoint buttonOrigin = cancelButton.frame.origin;
        CGSize buttonSize = cancelButton.frame.size;
        CGFloat buttonTravelDist = buttonSize.width + 10.0f;
        CGPoint onscreenPos = CGPointMake(buttonOrigin.x + buttonTravelDist, buttonOrigin.y);

        cancelButton.frame = CGRectMake(onscreenPos.x, onscreenPos.y, buttonSize.width, buttonSize.height);

        CGPoint fieldOrigin = searchField.frame.origin;
        CGSize fieldSize = searchField.frame.size;

        searchField.frame = CGRectMake(fieldOrigin.x, fieldOrigin.y, fieldSize.width + buttonTravelDist, fieldSize.height);
    }];
}

This has completely fixed the situation for me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文