编辑后,UITextField中的文本会向上移动(在编辑时居中)

45
我有一个奇怪的问题。我有一个UITextField,用户应该在其中写下某物的数量,所以该字段称为“amountField”。当用户开始编辑文本字段时,文本处于垂直和水平居中状态 - 这很棒。
然而,当用户结束编辑后,文本会向上移动一点。我尝试了很多方法,没有什么帮助...
我将添加以下截图,这样您就可以看到问题所在。
这是编辑该字段时的样子 - 没问题。 This is while editing the field - that's ok. 这是完成编辑后的样子 - 这就是问题所在! This is the problem. 如果有人知道可能导致这种问题的原因,请告诉我,我将不胜感激! :)
这是与amountField相关的一些代码。
amountField.keyboardType = UIKeyboardTypeNumberPad;
amountField.returnKeyType = UIReturnKeyDone;
amountField.delegate = self;

[amountField setFont:[UIFont fontWithName:@"Nuptial Script LT Std" size:30]];   
amountField.borderStyle = UITextBorderStyleNone;
UIImage *amountBg = [UIImage imageNamed:@"skin2_ipad_amountField.png"];
[amountField setBackground:amountBg];

amountField.rightView = nil;
//amountField.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.2];

amountField.textAlignment = UITextAlignmentCenter;
amountField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
amountField.adjustsFontSizeToFitWidth = YES;
amountLabel.textColor = UIColorFromARGB(0x313030); //Using my own macro

amountField.frame = CGRectMake(300, 480, 136, 32);
amountField.center = CGPointMake(605, 439);

提示:那些白色角落的存在是因为我将背景设为了0.2透明度的白色,这没问题。


1
有进展吗?我的文本字段也遇到了同样的问题。 - Steven Baughman
我很高兴不是唯一一个遇到这个问题的人,我尝试了所有能想到的方法... 我会立即报告任何进展,所以请继续关注这个问题 :) - Dominik Hadl
@erkanyildiz 是的,你说得对,我也是遇到同样问题的第二个人.....!!! 好的,感谢您让我走上了正确的轨道..!!!! - Kamar Shad
13个回答

52

我遇到了一个类似的问题,这个问题始于iOS 9。基本上,我在一个集合视图单元格中有一个UITextField。有时,当用户完成输入并结束编辑时,文本会"弹跳",然后再次回到正确的位置。非常奇怪和烦人的故障。只需进行这个小调整就能解决iOS 9上的问题,并且在iOS 7和8上也被证明是安全的:

 - (void)textFieldDidEndEditing:(UITextField *)textField
 {
    [textField layoutIfNeeded]; //Fixes iOS 9 text bounce glitch
    //...other stuff
}

我也遇到了这个问题,我有公司名称、用户名和密码三个UITextField排成一行。但我的症状不仅出现在iOS 9上,也出现在iOS 8上。我怀疑这与Xcode 7.0有关?在iOS 8.3、8.4模拟器上也会出现这种情况。还没有8.x设备进行测试。但你的解决方案适用于两个版本。这就是为什么我认为它与Xcode 7或iOS 9 SDK有关。 - Wingzero
1
我在使用Xcode 6构建iOS 8时遇到了这个问题。在我解决它之前,我升级到了Xcode 7并开始构建iOS 9。然后我再也没有看到这个错误了。 - peacetype
我在iOS 9.0.2上也遇到了同样的问题。 - wasabi
1
iOS 9.0.2上有相同的错误。 - pronebird
3
同样的Bug在10.1.1版本上出现了,拜托Apple了。顺便说一下,这个修复似乎仍然很好用。 - bfich

23

经过多个小时的尝试,我找到了问题所在。

在我的情况下,问题出在字体上。我真的不知道为什么,但是字体作者使字体变得奇怪(行间距等),它底部还有一个空白空间。我不知道为什么,但是当您编辑文本时,所有文本属性都被忽略,但是在完成编辑后,它们会应用。

因此,如果您有类似的问题,请尝试将字体更改为Arial或类似字体。

要获取完整说明,请参阅以下链接:链接1链接2。这些链接推荐的解决方案可以避免许多头疼的问题,甚至可以应用于修复像使用系统字体或其他特定字体时开始编辑UITextField时文本向上移动的问题。


我也在使用自定义字体。很奇怪。我的解决方案是在用户停止更新时更新字体框架,以确保它看起来垂直居中。 - Steven Baughman
很高兴听到它对你有帮助 :) (如果你想的话,可以给我的答案点赞)你是如何更新字体框架的?你能贴出一部分代码吗? :) 谢谢,Dominik - Dominik Hadl
6
不要改变字体,试试这个方法。https://dev59.com/6Gw15IYBdhLWcg3w3fjN#10087220 - McDJ
@McDJ,你的答案只是其中一种潜在的解决方案,仅修复了一个特定情况(字体类型、字体大小和UITextField高度的组合加上一些方法覆盖)。请看下面我详尽的回答,你将会看到并学习到其他修复这个iOS故障的方法。 - King-Wizard
@Dominik Hadl,您提供的解决方案只是一种hack方法,它仅适用于一种字体和大小,一旦更改字体大小和/或字体类型,该错误就会重新出现。因此,这不是解决所有情况(字体类型、字体大小和UITextField高度的组合)的解决方案,它只是在一个特定情况下临时修复错误的hack方法。解决此问题的其他方法如我在下面提到的(请参见我的答案),可以通过反编译和修改字体,或更改字体类型和/或字体大小和/或界面生成器中的UITextField高度来实现。 - King-Wizard
经过数小时的调试,删除布局约束,删除自定义样式...终于找到了你的帖子 :) HelveticaNeue 是导致问题的罪魁祸首(在我的情况下) 谢谢,伙计 :) +1 赞 ;) - zvjerka24

8
禁用TextField的ClipsToBounds属性对我有所帮助。

你的解决方案帮了我很大忙。能否解释一下它为什么有效? - alanhchoi
2
我的猜测是,由于光标比文本更高,当您使文本字段成为第一响应者并启用剪辑到边界时,必须重新绘制文本以适合文本和光标。我们看到的是重新绘制。当您禁用剪辑到边界时,不再约束文本字段的垂直位置,因此不会发生重新绘制或更新。@hoseokchoi - Alexis Candelaria

4

当我在 viewDidLoadviewWillAppear 中设置文本并成为第一响应者时,出现了这个 bug。当我将 becomeFirstResponder 代码移到 viewDidAppear 中时,该 bug 消失了。


1
这个加上 @n8tr 的回答解决了我的一些奇怪问题。推荐。 - Sam Soffes

2

每当应用程序的设计涉及自定义字体时,我总是遇到这个问题。一种解决方案是固定字体(但这对我来说太麻烦了:))。我使用的第二种选择是子类化UITextField并覆盖editingRectForBounds:和placeholderRectForBounds:方法,并校正偏移量。这也适用于您的情况。

@implementation MyTextFieldWithFixedFontPosition

-(CGRect)editingRectForBounds:(CGRect)bounds{
    return CGRectOffset([self textRectForBounds:bounds], 0, 0.5); //0.5 is just example, you can adjust to any offset you like
}
-(CGRect)placeholderRectForBounds:(CGRect)bounds{
    return [self editingRectForBounds:bounds];
}

@end

我还没有测试过leftView或者rightView,所以在使用这些功能时请小心 :)

注意:这种方法是“字体相关”的,偏移量的值可能因字体和大小而异。


是的,没错。在字体大小计算中也应该考虑到偏移量,因为不同的字体可能会有不同的偏移量。 - JakubKnejzlik

1
在 iOS 8.1 及以下版本存在一个故障,我不知道以后是否会修复它,但那个时候没有一种独特的解决方案可以修复所有情况,因为错误和解决方案取决于字体的类型和大小。
以下其中一个解决方案或这些解决方案的组合可以解决您的问题:
- 更改字体大小。 - 更改字体类型。 - 更改 UITextField 的大小。 - 对涉及到的字体进行反编译、修改其特性并重新编译(有关详细说明,请参阅以下链接: link 1 link 2)。
否则,以下另一个自给自足的解决方案可以解决您的问题: Swift 版本
import UIKit

class CustomTextField: UITextField {

    ...

    override func textRectForBounds(bounds: CGRect) -> CGRect {
        // Possible values.
        return CGRectInset(bounds, CGFloat(35.0), CGFloat(0.0))
    }

    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        // Possible values.
        return CGRectInset(bounds, CGFloat(35.0), CGFloat(0.0))
    }

    override func placeholderRectForBounds(bounds: CGRect) -> CGRect {
        // Possible values.
        return CGRectInset(bounds, CGFloat(35.0), CGFloat(0.0))
    }

}

这个解决方案已经与leftView一起测试,效果非常好。
注意:这种方法是“字体相关的”,CGRectInset使用的值可能因不同的字体和大小而有所不同。

您能解释一下为什么使用插入和返回相同的文本/编辑文本/占位符框架可以解决问题吗?在我的大多数情况下,问题是当返回相同的矩形时字体呈现不正确(移动)。 - JakubKnejzlik
@GrizzlyNetch 设置插图是一个花哨的句子,意思是设置UITextField内文本周围的填充。在这里,您可以找到单词插图的定义:http://www.thefreedictionary.com/inset - King-Wizard
@GrizzlyNetch 如果第一次尝试不成功,那很正常,因为如我在答案中所说:这种方法是“字体相关的”,CGRectInset使用的值可能因字体和大小而异。 - King-Wizard
你给我们的解决方案只是一个临时的hack,它只适用于一种字体和大小,一旦你改变字体的大小和/或字体类型,这个bug就会再次出现。因此,它不是一个可以解决所有情况(字体类型、字体大小和UITextField高度的组合)的解决方案,它只是一个临时的hack,可以在特定情况下暂时修复这个bug。解决这个问题的其他方法可能是反编译和修改字体,或者在界面构建器中更改字体类型、字体大小和/或UITextField的高度。 - Blacky
@King-Wizard,您在此帖中的行为不符合Stack Overflow成为良好用户的理想准则。您已经在几乎每个评论中都发布垃圾信息,这使得有价值的信息难以在所有自我推销的垃圾信息中找到。请参考http://stackoverflow.com/help/behavior。 - jungledev
显示剩余2条评论

1
我通过给UITextFields添加高度约束来解决了这个问题。

0

我之前在一个UITableViewCell嵌套的UITextfield上也遇到过类似的问题。这段代码在你的工程中的具体位置是哪里?我认为问题出在当你完成编辑特定的textfield后,它会发送自己一个-setNeedsDisplay并随后调用drawRect:方法。这可能解释了对齐方式变化的原因。在我的情况下,我不得不使用一个表视图代理方法-willDisplayCell...来设置内容对齐方式。如果要提供建议,我需要更多关于你设计的信息。

一个潜在的解决方案是使用文本字段委托方法来设置内容对齐方式。

-(void)textFieldDidEndEditing:(UITextField *)textField{
     if (amountField == textField){
          amountField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
        }
}

谢谢您的回答 :) 我在上班,回家后会试试。 - Dominik Hadl

0

这些解决方案对我不起作用。我的解决方案是子类化UITextField并重写setText:

- (void) setText:(NSString *)text {
    [super setText:text];
    [self layoutIfNeeded];
}

0
这是因为文本字段的BaselineOffset被更改了。 在UITextFieldDidEndEditing中使用NSBaselineOffset:0创建带属性文本,并使用该attributedText可以解决问题。
-(IBAction)txtFieldDidEndEditing:(UITextField *)sender {
     NSDictionary *style = @{
                            NSBaselineOffsetAttributeName: @(0)
                            };
    self.txtField.attributedText = [[NSAttributedString alloc] initWithString:self.txtField.text attributes:style];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接