user1406716
user1406716

Reputation: 9705

How to only show bottom border of UITextField in Swift

I want to show only bottom border and hide the other sides.

Output I see: As you can see I see the top, left and right borders also and they are black in color, I want to remove them. Only need the bottom white thick 2.0 border.

enter image description here

Code I am using (source):

var border = CALayer()
var width = CGFloat(2.0)
border.borderColor = UIColor.whiteColor().CGColor
border.frame = CGRect(x: 0, y: tv_username.frame.size.height - width, width: tv_username.frame.size.width, height: tv_username.frame.size.height)

border.borderWidth = width
tv_username.backgroundColor = UIColor.clearColor()
tv_username.layer.addSublayer(border)
tv_username.layer.masksToBounds = true
tv_username.textColor = UIColor.whiteColor()

Upvotes: 30

Views: 70022

Answers (14)

andrewlundy_
andrewlundy_

Reputation: 1143

Swift 5.

extension UITextField {
    let bottomLine = UIView()
    bottomLine.backgroundColor = .black
    borderStyle = .none
        
    self.addSubview(bottomLine)

    NSLayoutConstraint.activate([
        bottomLine.topAnchor.constraint(equalTo: bottomAnchor + 10),
        bottomLine.leadingAnchor.constraint(equalTo: leadingAnchor),
        bottomLine.trailingAnchor.constraint(equalTo: trailingAnchor),
        bottomLine.heightAnchor.constraint(equalToConstant: 1)
    ]) 
}

Upvotes: 1

rami
rami

Reputation: 182

Using extension and Swift 5.3

extension UITextField {
    internal func addBottomBorder(height: CGFloat = 1.0, color: UIColor = .black) {
        let borderView = UIView()
        borderView.backgroundColor = color
        borderView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(borderView)
        NSLayoutConstraint.activate(
            [
                borderView.leadingAnchor.constraint(equalTo: leadingAnchor),
                borderView.trailingAnchor.constraint(equalTo: trailingAnchor),
                borderView.bottomAnchor.constraint(equalTo: bottomAnchor),
                borderView.heightAnchor.constraint(equalToConstant: height)
            ]
        )
    }
}

Upvotes: 4

Santi
Santi

Reputation: 1

For swift 4. this works for me.

   let myfield:UITextField = {
        let mf=UITextField()
        let atributePlaceHolder=NSAttributedString(string: "Text_description", attributes:[NSAttributedString.Key.foregroundColor :UIColor.darkGray])
        mf.textColor = .gray
        mf.attributedPlaceholder=atributePlaceHolder
        mf.layer.borderColor = UIColor.black.cgColor
        mf.layer.backgroundColor = UIColor.white.cgColor
        mf.layer.borderWidth = 0.0
        mf.layer.shadowOffset = CGSize(width: 0, height: 1.0)
        mf.layer.shadowOpacity = 1.0
        mf.layer.shadowRadius = 0.0
        return mf
    }()

Upvotes: 0

smakus
smakus

Reputation: 1417

For those looking for a solution that works for Autolayout, IBInspectable, and the Storyboard, subclass UITextField into your custom textfield class and add these:

func setUnderline() {
    for sub in self.subviews {
        sub.removeFromSuperview()
    }
    if underlineStyle == true {
        var bottomBorder = UIView()
        bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        bottomBorder.backgroundColor = borderColor  //YOUR UNDERLINE COLOR HERE
        bottomBorder.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(bottomBorder)

        bottomBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
        bottomBorder.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
        bottomBorder.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        bottomBorder.heightAnchor.constraint(equalToConstant: underlineHeight).isActive = true
        layoutIfNeeded()
    }
}

@IBInspectable var underlineStyle: Bool = false {
    didSet {
       setUnderline()
    }
}

@IBInspectable var underlineHeight: CGFloat = 0 {
    didSet {
        setUnderline()
    }
}

Upvotes: 2

meow2x
meow2x

Reputation: 2124

First set borderStyle property to .none.

Also, don't forget that the best time to call this method in the viewDidAppear(_:) method.

To make it handy, you can use an extension:

extension UIView {
    func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
        let border = CALayer()
        border.backgroundColor = color.cgColor
        border.frame = CGRect(x: 0, y: self.frame.size.height - width, 
                              width: self.frame.size.width, height: width)
        self.layer.addSublayer(border)
    }
}

Call it like:

textfield.addBottomBorderWithColor(color: UIColor.lightGray, width: 0.5)

Upvotes: 3

Ashish Kakkad
Ashish Kakkad

Reputation: 23872

Try to do by this way, with Swift 5.1:

var bottomLine = CALayer()
bottomLine.frame = CGRect(x: 0.0, y: myTextField.frame.height - 1, width: myTextField.frame.width, height: 1.0)
bottomLine.backgroundColor = UIColor.white.cgColor
myTextField.borderStyle = UITextField.BorderStyle.none
myTextField.layer.addSublayer(bottomLine)

You have to set the borderStyle property to None

If you are using the autolayout then set perfect constraint else bottomline will not appear.

Hope it helps.

Upvotes: 73

Vitaliy
Vitaliy

Reputation: 25

Solution which using CALayer is not good because when device is rotated the underline doesn't change width.

class UnderlinedTextField: UITextField {

    override func awakeFromNib() {
        super.awakeFromNib()

        let bottomLine = CALayer()
        bottomLine.frame = CGRect(x: 0, y: self.frame.size.height, width: UIScreen.main.bounds.width, height: 1)
        bottomLine.bounds = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: self.frame.size.height)
        bottomLine.backgroundColor = UIColor.black.cgColor
        borderStyle = .none
        layer.addSublayer(bottomLine)
        layer.masksToBounds = true
    }
}

The best solution is to use UIView.

class UnderlinedTextField: UITextField {
    private let defaultUnderlineColor = UIColor.black
    private let bottomLine = UIView()

    override func awakeFromNib() {
        super.awakeFromNib()

        borderStyle = .none
        bottomLine.translatesAutoresizingMaskIntoConstraints = false
        bottomLine.backgroundColor = defaultUnderlineColor

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

    public func setUnderlineColor(color: UIColor = .red) {
        bottomLine.backgroundColor = color
    }

    public func setDefaultUnderlineColor() {
        bottomLine.backgroundColor = defaultUnderlineColor
    }
}

Upvotes: 3

iBug
iBug

Reputation: 2342

Thought from @Ashish's answer, used same approach long ago in Objective-C but implementing extension will be more useful.

extension UITextField {
    func addBottomBorder(){
        let bottomLine = CALayer()
        bottomLine.frame = CGRect(x: 0, y: self.frame.size.height - 1, width: self.frame.size.width, height: 1)
        bottomLine.backgroundColor = UIColor.white.cgColor
        borderStyle = .none
        layer.addSublayer(bottomLine)
    }
}

In your controller:

self.textField.addBottomBorder()

Can add further parameters to your method, like adding border height, color.

Upvotes: 18

Wackerow
Wackerow

Reputation: 71

@mina-fawzy I liked the answer that included masksToBounds by Mina Fawzy...

I ran into this issue where I was trying to style a bottom border of a UITextField, and the comments using a CGRect worked for me, however, I ran into issues when using different screen sizes, or if I changed the orientation to landscape view from the portrait.

ie. My Xcode Main.storyboard was designed with iPhone XS Max, with a UITextField constrained to be 20 points from the left/right of the screen. In my viewDidLoad() I stylized the UITextField (textfield) using the CGRect approach, making the width of the rectangle equal to textfield.frame.width.

When testing on the iPhone XS Max, everything worked perfectly, BUT, when I tested on iPhone 7 (smaller screen width) the CGRect was grabbing the width of the iPhone XS Max during the viewDidLoad(), causing the rectangle (bottom line) to be too wide, and the right edge went off the screen. Similarly, when I tested on iPad screens, the bottom line was way too short. And also, on any device, rotating to landscape view did not re-calculate the size of the rectangle needed for the bottom line.

The best solution I found was to set the width of the CGRect to larger than the longest iPad dimension (I randomly chose 2000) and THEN added textfield.layer.masksToBounds = true. This worked perfectly because now the line is plenty long from the beginning, does not need to be re-calculated ever, and is clipped to the correct width of the UITextField no matter what screen size or orientation.

Thanks Mina, and hope this helps others with the same issue!

Upvotes: 7

Srinivasan_iOS
Srinivasan_iOS

Reputation: 1078

Textfield bottom border set but some more issues for devices.So bottom border not fit in textfield.I retrieve that problem the code like this It works fine swift 4.2

let bottomLine = CALayer()
        bottomLine.frame = CGRect(x: 0.0, y: textField.frame.height - 1, width: screenSize.width - 32, height: 1.0)
        bottomLine.backgroundColor = UIColor(hex: 0xD5D5D5).cgColor
        textField.borderStyle = UITextField.BorderStyle.none
        textField.layer.addSublayer(bottomLine)

Upvotes: 0

Codetard
Codetard

Reputation: 2595

Swift 3:

Just subclass your UITextField

class BottomBorderTF: UITextField {

var bottomBorder = UIView()
override func awakeFromNib() {

    //MARK: Setup Bottom-Border
    self.translatesAutoresizingMaskIntoConstraints = false
    bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
    bottomBorder.backgroundColor = UIColor.orange
    bottomBorder.translatesAutoresizingMaskIntoConstraints = false
    addSubview(bottomBorder)
    //Mark: Setup Anchors
    bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
    bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
    bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set Border-Strength

   }
}

Upvotes: 6

garg
garg

Reputation: 2727

For multiple Text Field

  override func viewDidLoad() {


    configureTextField(x: 0, y: locationField.frame.size.height-1.0, width: locationField.frame.size.width, height:1.0, textField: locationField)
    configureTextField(x: 0, y: destinationField.frame.size.height-1.0, width: destinationField.frame.size.width, height:1.0, textField: destinationField)
    configureTextField(x: 0, y: originField.frame.size.height-1.0, width: originField.frame.size.width, height:1.0, textField: originField)
    configureTextField(x: 0, y: nameField.frame.size.height-1.0, width: nameField.frame.size.width, height:1.0, textField: nameField)

    locationField.text="Hello"
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

func configureTextField(x:CGFloat,y:CGFloat,width:CGFloat,height:CGFloat,textField:UITextField)

{
    let bottomLine = CALayer()
    bottomLine.frame = CGRect(x: x, y: y, width: width, height: height)
    bottomLine.backgroundColor = UIColor.white.cgColor
    textField.borderStyle = UITextBorderStyle.none
    textField.layer.addSublayer(bottomLine)


}

Upvotes: 0

Mina Fawzy
Mina Fawzy

Reputation: 21452

I have tried all this answer but no one worked for me except this one

  let borderWidth:CGFloat = 2.0 // what ever border width do you prefer 
    let bottomLine = CALayer()

    bottomLine.frame = CGRectMake(0.0, Et_textfield.height  - borderWidth, Et_textfield.width, Et_textfield.height )
    bottomLine.backgroundColor = UIColor.blueColor().CGColor
    bottomLine
    Et_textfield.layer.addSublayer(bottomLine)
    Et_textfield.layer.masksToBounds = true // the most important line of code

Upvotes: 6

Mitul Marsoniya
Mitul Marsoniya

Reputation: 5299

Objective C

[txt.layer setBackgroundColor: [[UIColor whiteColor] CGColor]];
[txt.layer setBorderColor: [[UIColor grayColor] CGColor]];
[txt.layer setBorderWidth: 0.0];
[txt.layer setCornerRadius:12.0f];
[txt.layer setMasksToBounds:NO];
[txt.layer setShadowRadius:2.0f];
txt.layer.shadowColor = [[UIColor blackColor] CGColor];
txt.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
txt.layer.shadowOpacity = 1.0f;
txt.layer.shadowRadius = 1.0f;

Swift

textField.layer.backgroundColor = UIColor.whiteColor().CGColor
textField.layer.borderColor = UIColor.grayColor().CGColor
textField.layer.borderWidth = 0.0
textField.layer.cornerRadius = 5
textField.layer.masksToBounds = false
textField.layer.shadowRadius = 2.0
textField.layer.shadowColor = UIColor.blackColor().CGColor
textField.layer.shadowOffset = CGSizeMake(1.0, 1.0)
textField.layer.shadowOpacity = 1.0
textField.layer.shadowRadius = 1.0

Upvotes: 6

Related Questions