Using a custom font in a UITextField causes it to shift slightly upon access - is there a fix?

I have a custom font in UITextField, and I noticed that when it opens (when the keyboard appears), the text is shifted by a very small amount - maybe a pixel or two or three. (Of course, I canโ€™t measure it, but itโ€™s enough for me to notice). And then when the keyboard deviates, it goes back again.

I tried to clear the field when editing (which hides the problem of the initial shift down), but it did not solve the problem. I also looked at various attributes in IB and tried to change a few, but the problem still persists. I get the same results in the simulator and on my iPad2.

(The field is clearly visible from the keyboard, so not all of the view moves to the side - it's just the contents of this particular text field.)

I am sure that this is a custom font that causes the problem - without it.

Any idea how to solve this problem? I thought that I might need to create a text box programmatically and not in IB - and I know that I probably should try this before asking this question here, but I cannot go for all these problems if it will not solve the problem.

Any advice appreciated!

+23
uitextfield xcode4 interface-builder embedded-fonts
Jun 14 '11 at 23:24
source share
10 answers

I had this problem too.

To fix, subclass UITextField and implement the following methods for adjusting the positioning of text when editing and editing.

 - (CGRect)textRectForBounds:(CGRect)bounds { return CGRectInset( bounds , 8 , 8 ); } - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectInset( bounds , 8 , 5 ); } 
+15
Apr 10 2018-12-12T00:
source share
โ€” -

My solution is the same lines as McDJ, but with a slightly different twist. Subclass UITextField and override only the following:

 - (CGRect)placeholderRectForBounds:(CGRect)bounds { return CGRectOffset( [self editingRectForBounds:bounds], 0, 2 ); } - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectOffset( [super editingRectForBounds:bounds], 0, -2 ); } 

Using a custom font that I use, 2 points - this is the correct vertical setting to help the placeholder, the "static" and "editing" text remain on the same vertical line.

+3
Sep 09 '12 at 21:50
source share

Unfortunately, none of the answers worked for me.

Answer to

@blackjacx worked, but only sometimes :(

I started debugging, and here is what I found:

1 - The real problem seems to be related to the closed UITextField subtitle of type UIFieldEditorContentView

UITextField view hieararchy

Below you can see that the y this subview does not match the UITextField itself:

Y is not set to 0

Realizing this, I came up with the following workaround:

 override func layoutSubviews() { super.layoutSubviews() fixMisplacedEditorContentView() } func fixMisplacedEditorContentView() { if #available(iOS 10, *) { for view in subviews { if view.bounds.origin.y < 0 { view.bounds.origin = CGPoint(x: view.bounds.origin.x, y: 0) } } } } 

You will need to subclass UITextField and override layoutSubviews to add the ability to manually set the 0 y any subhead set to a negative value. Since this problem does not occur with iOS 9 below, I added a check to make a workaround only when it is on iOS 10.

The result you can see below:

Working right

2 - This workaround does not work if the user selects a text submenu (selectAll works fine)

Since text selection is not required for my application, I would rather disable it. For this you can use the following code (Swift 3):

 override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if #available(iOS 10, *) { if action == #selector(UIResponderStandardEditActions.select(_:)) { return false } } return super.canPerformAction(action, withSender: sender) } 
+2
Apr 13 '17 at 19:29
source share

Works for all font sizes and does not cause alignment with clearButton .

Subclass UITextField and override them as follows:

 - (CGRect)placeholderRectForBounds:(CGRect)bounds { return CGRectOffset( bounds, 0, 4 ); } - (CGRect)editingRectForBounds:(CGRect)bounds { return CGRectOffset( bounds, 0, 2); } - (CGRect)textRectForBounds:(CGRect)bounds { return CGRectOffset( bounds , 0 , 4 ); } 
+1
Nov 13
source share

For a strange reason, I really didnโ€™t understand that I solved this by setting autoAdjustsScrollViewInsets to NO (or the equivalent in Interface Builder). This is with iOS 8.1.

+1
Feb 24 '16 at 17:13
source share

I had this problem with a custom font and was resolved by sliding the shortcut in the other direction when keyboard events would occur. I moved the center of the label to the button, overriding the drawRect: method drawRect:

 - (void)drawRect:(CGRect)rect { self.titleLabel.center = CGPointMake(self.titleLabel.center.x, self.titleLabel.center.y+3); } 
0
Feb 03 '12 at 3:27
source share

This is the expected behavior in a standard UITextField. However, you can solve this by subclassing UITextField and setting the borders for the text itself.

Swift 3

 override func textRect(forBounds bounds: CGRect) -> CGRect { return(bounds.insetBy(dx: 0, dy: 0)) } override func editingRect(forBounds bounds: CGRect) -> CGRect { return(bounds.insetBy(dx: 0, dy: -0.5)) } override func placeholderRect(forBounds bounds: CGRect) -> CGRect { return(bounds.insetBy(dx: 0, dy: 0)) } 

That should do the trick!

0
Oct. 27 '16 at 11:18
source share

Set your Border Style text boxes to any value except "none" in IB, and then in your ViewController viewDidLoad set:

 yourTextField.borderStyle = .none 

(Based on this answer from Box Jeon)

0
Feb 02 '17 at 22:25
source share

Swift 3

Do not forget accessory views UITextField. You will need to specify super functions * rect (forBounds: ...) if you want to do a working implementation. And rest assured that just squeeze out the rectangles for the iOS 10 buggy, not 9 or 8! The following code should do the trick:

 public class CustomTextField: UITextField { public override func textRect(forBounds bounds: CGRect) -> CGRect { let superValue = super.textRect(forBounds: bounds) if #available(iOS 10, *) { return superValue.insetBy(dx: 0, dy: 0) } return superValue } public override func editingRect(forBounds bounds: CGRect) -> CGRect { let superValue = super.editingRect(forBounds: bounds) if #available(iOS 10, *) { return superValue.insetBy(dx: 0, dy: -0.5) } return superValue } public override func placeholderRect(forBounds bounds: CGRect) -> CGRect { let superValue = super.placeholderRect(forBounds: bounds) if #available(iOS 10, *) { if isEditing { return superValue.insetBy(dx: 0, dy: 0.5) } return superValue.insetBy(dx: 0, dy: 0.0) } return superValue } } 

EDIT

I changed my code a bit from the top to the next and it works better for me. I am testing it on iPhone 6, 6s, 7, 7s, as well as on plus devices with iOS 9.3 and 10.3.

 public class CustomTextField: UITextField { public override func textRect(forBounds bounds: CGRect) -> CGRect { let superValue = super.textRect(forBounds: bounds) if #available(iOS 10, *) { return superValue.insetBy(dx: 0, dy: -0.3) } return superValue.insetBy(dx: 0, dy: -0.2) } public override func editingRect(forBounds bounds: CGRect) -> CGRect { return self.textRect(forBounds: bounds) } } 

I think it also depends on the font you are using. I am using UIFont.systemFont(ofSize: 17.0, weight: UIFontWeightLight)

0
Apr 05 '17 at 23:44 on
source share

You must set the font property before the Text property.

-one
Apr 30 '14 at 11:33
source share



All Articles