Timothy
Timothy

Reputation: 152

UITextField frame width being returned too short?

I have a UITextField which I am applying a bottom border to, using the following method in a UITextField category:

-(void)addBottomBorder {
    CALayer *border = [CALayer layer];
    CGFloat borderWidth = 1;

    //  For the sake of visibility
    border.borderColor = [UIColor redColor].CGColor;
    self.backgroundColor = [UIColor whiteColor];

    border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, self.frame.size.height);
    border.borderWidth = borderWidth;

    [self.layer addSublayer:border];

    self.layer.masksToBounds = YES;
}

The funny thing is that the red bottom border is not spanning the entire width of the text field.

Here's a screenshot of the behavior. Any ideas as to what might be causing this? hmmm?

Upvotes: 2

Views: 1143

Answers (9)

besam
besam

Reputation: 155

I use this function to styling my text fields:

    static func styleTextField(_ textfield:UITextField) {
    textfield.borderStyle = .none

    let bottomLine = UIView()
    bottomLine.backgroundColor = UIColor.Black
    bottomLine.translatesAutoresizingMaskIntoConstraints = false

    textfield.addSubview(bottomLine)
    bottomLine.topAnchor.constraint(equalTo: textfield.bottomAnchor, constant: 1).isActive = true
    bottomLine.leadingAnchor.constraint(equalTo: textfield.leadingAnchor).isActive = true
    bottomLine.trailingAnchor.constraint(equalTo: textfield.trailingAnchor).isActive = true
    bottomLine.heightAnchor.constraint(equalToConstant: 1).isActive = true
}

Then maybe Call the function in viewDidLoad and input target textfield:

styleTextField(textfield)

Upvotes: 0

Xavier Chia
Xavier Chia

Reputation: 257

I moved my addSublayer to viewDidAppear instead of viewDidLoad and it worked fine :D

Upvotes: 0

Ahmed Elashker
Ahmed Elashker

Reputation: 1000

Simply add the border drawing call inside setNeedsLayout instead of awakeFromNib

Then from the view controller call subview's setNeedsLayout from viewDidLayoutSubviews

If you have many subviews needing to apply the same effect, it's better to gather them all in an outlet collection inside a base class you'll create. You will use this base class to inherit in all your view controllers including your custom text field.

@interface FieldsViewController () 

@property (strong, nonatomic) IBOutletCollection(CustomTextField) NSArray *textFields;

@end

@implementation FieldsViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewDidLayoutSubviews {
    for (CustomTextField *textField in self.textFields) {
        [textField setNeedsLayout];
    }
}

@end

Upvotes: 0

pronebird
pronebird

Reputation: 12230

Sublayers aren't automatically positioned. You do not layout your sublayer.

Do not mess with text field, instead wrap it in decoration view and add background color or something with 2 pixel padding at the bottom.

Upvotes: 0

Sanjay Mohnani
Sanjay Mohnani

Reputation: 5967

If you are using autoresizing masks, like flexible width of view, textfield e.t.c, than in that case you should add the border layer after your views are successfully resized according to the resolutions and auto resizing constraints.

The problem in your case looks like that you have a text field on which you added layer with the present dimensions of text filed and after adding layer the text field is resized as per auto resizing constraints. But the layer was not resized as per the constraints and has the earlier dimension which results in the difference in width between your text field and the border layer.

To resolve this issue you should add your border layer after the text filed is resized.

Alternatively, create a 1 pixel UIView below the text filed and set it's horizontal autoresizing masks same as the text filed.

Upvotes: 4

zrzka
zrzka

Reputation: 21219

So many issues there ...

  • what if your UITextField will resize?
  • what if there will be leftView / rightView and they obscure underlying view?
  • if you're adding subview, you should use bounds, not frame
  • what if bounds.origin.x != 0? same for bounds.origin.y

... the easiest way is to do what Kristaps recommends.

Upvotes: 2

Kristaps Vītols
Kristaps Vītols

Reputation: 56

It would be easier to create a UIView that is 1p high and pinned to the bottom and sides with constraints in Storyboard. Your problem, from what I understand, only happens when your textField width on screen is above the size it has in the storyboard, because the textField gets stretched AFTER the bottom line has been added thus it does not stretch along with the field.

Upvotes: 1

DavidWeldon
DavidWeldon

Reputation: 121

Is the problem that the border's layer is being obscured by the rightView? Could you try adding the border, in UIView form, as a subview of the text view?

Upvotes: 0

yaboi
yaboi

Reputation: 411

Try setting the color after you set borderWidth

Upvotes: 0

Related Questions