iOS add / remove shadow from a view - ios

I do not understand how to remove a shadow that was added to a view.
I add to my view in initWithFrame a shadow in this way:
self.layer.borderWidth = 2;
self.layer.borderColor = [UIColor clearColor].CGColor;
self.backgroundColor = [UIColor greenColor];
[self.layer setCornerRadius:8.0f];
CALayer *layer = self.layer;
layer.shadowOffset = CGSizeMake(2, 2);
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.cornerRadius = 8.0f;
layer.shadowRadius = 3.0f;
layer.shadowOpacity = 0.80f;
layer.shadowPath = [[UIBezierPath bezierPathWithRect:layer.bounds] CGPath];
After in the execution of the app I want to remove the shadow from this view. I've tried using:
layer.hidden = YES;
or
self.layer.hidden = YES;
but this hides the view completely, not just the added shadow.
Is there a way to retrieve the added shadow from a view and then hide it?
Thanks!

I guess you could use the shadowOpacity property of your CALayer.
So this should work:
self.layer.shadowOpacity = 0;
See the CALayer's shadowOpacity documentation page
And to show your shadow use:
self.layer.shadowOpacity = 1.0;

Sorry, not sure the correct way, but have you tried changing the properties of the layer shadow? For example, one of these;
layer.shadowOffset = CGSizeMake(0, 0);
layer.shadowColor = [[UIColor clearColor] CGColor];
layer.cornerRadius = 0.0f;
layer.shadowRadius = 0.0f;
layer.shadowOpacity = 0.00f;

Swift 4.2
I am using this in my code for labels and navigation bar.
extension UIView {
func shadow(_ height: Int = 5) {
self.layer.masksToBounds = false
self.layer.shadowRadius = 4
self.layer.shadowOpacity = 1
self.layer.shadowColor = UIColor.gray.cgColor
self.layer.shadowOffset = CGSize(width: 0 , height: height)
}
func removeShadow() {
self.layer.shadowOffset = CGSize(width: 0 , height: 0)
self.layer.shadowColor = UIColor.clear.cgColor
self.layer.cornerRadius = 0.0
self.layer.shadowRadius = 0.0
self.layer.shadowOpacity = 0.0
}
}

I tried the other answers, the only thing that worked for me was to toggle layer.masksToBounds to true/false
lazy var myView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
view.layer.cornerRadius = 5
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 3
view.layer.shadowOffset = .zero
view.layer.shadowRadius = 5
return view
}()
func showShadow() {
myView.layer.masksToBounds = false
}
func hideShadow() {
myView.layer.masksToBounds = true
}

the "layer" that you are trying to make hidden is the layer of the object that you are having a shadow to it's not a visible aspect.. only the objects with in the layer... it's rather confusing to conceptualize anyways, the only way to remove the shadow is to undo what you originally did, which was suggested above, there is no defined property that you can just toggle a bool and make the shadow go away

Swift 5.+
My solution was to add a shadowBackgroundView, which has a removable shadowLayer. In this way I could easyly remove the layer without resetting the shadow properties.
class ViewController: UIViewController {
private let shadowBackgroundView: UIView = {
let view = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
view.layer.masksToBounds = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(shadowBackgroundView)
// the view you want to add the shadow
let dummyView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
dummyView.backgroundColor = .red
shadowBackgroundView.addSubview(dummyView)
let addShadowButton = UIButton(frame: CGRect(x: 100, y: 300, width: 140, height: 50))
addShadowButton.backgroundColor = .blue
addShadowButton.setTitle("Add Shadow", for: .normal)
addShadowButton.addTarget(self, action: #selector(addShadow), for: .touchUpInside)
let removeShadowButton = UIButton(frame: CGRect(x: 100, y: 450, width: 140, height: 50))
removeShadowButton.backgroundColor = .blue
removeShadowButton.setTitle("Remove Shadow", for: .normal)
removeShadowButton.addTarget(self, action: #selector(removeShadow), for: .touchUpInside)
view.addSubview(addShadowButton)
view.addSubview(removeShadowButton)
}
#objc
func addShadow() {
let shadowLayer = CALayer()
shadowLayer.name = "ShadowLayer"
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowOpacity = 1
shadowLayer.shadowOffset = .zero
shadowLayer.shadowRadius = 10
shadowLayer.shadowPath = UIBezierPath(rect: shadowBackgroundView.bounds).cgPath
// Otherwise the shadow will appear above the dummyView
shadowLayer.zPosition = -1
shadowBackgroundView.layer.addSublayer(shadowLayer)
}
#objc
func removeShadow() {
// Alternatively, you could also create the shadowLayer as a property, so you could call shadowLayer.removeFromSuperLayer()
shadowBackgroundView.layer.sublayers?.first { $0.name == "ShadowLayer" }?.removeFromSuperlayer()
}
}
As a Note, for the UITableViewCell, you wouldnt need to add a shadowBackgroundView, but you could add the shadowLayer directly to cell.view.layer, which serves as the backgroundView for the cell.contentView.

Swift 4.2
Just to add to the other answers, you could change the opacity through animation:
#IBAction func btnDidTap(_ sender: UICustomGestureRecognizer) {
guard let view = sender.view else {return}
if sender.state == .began {
UIView.animate(withDuration: 0.3,
animations: {
view.layer.shadowOpacity = 0
})
} else if sender.state == .ended {
UIView.animate(withDuration: 0.3,
animations: {
view.layer.shadowOpacity = 1
})
}
}

Related

Swift create extension for textfield shadow code

I have multiple textfield but all the textfield have same shadow effects, I need to use extension for that shadow code and use it shortly in viewdid load.
below code I am using
//MARK - Email TextField
email_textfield.borderStyle = .none
email_textfield.backgroundColor = UIColor.groupTableViewBackground // Use anycolor that give you a 2d look.
//To apply corner radius
email_textfield.layer.cornerRadius = email_textfield.frame.size.height / 2
//To apply border
email_textfield.layer.borderWidth = 0.25
email_textfield.layer.borderColor = UIColor.white.cgColor
//To apply Shadow
email_textfield.layer.shadowOpacity = 1
email_textfield.layer.shadowRadius = 1.0
email_textfield.layer.shadowOffset = CGSize.zero // Use any CGSize
email_textfield.layer.shadowColor = UIColor.lightGray.cgColor
//To apply padding
let paddingView : UIView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: email_textfield.frame.height))
email_textfield.leftView = paddingView
email_textfield.leftViewMode = UITextFieldViewMode.always
you can create extension like this
extension UITextField {
func applyCustomEffect() {
self.borderStyle = .none
self.backgroundColor = UIColor.groupTableViewBackground // Use anycolor that give you a 2d look.
//To apply corner radius
self.layer.cornerRadius = self.frame.size.height / 2
//To apply border
self.layer.borderWidth = 0.25
self.layer.borderColor = UIColor.white.cgColor
//To apply Shadow
self.layer.shadowOpacity = 1
self.layer.shadowRadius = 1.0
self.layer.shadowOffset = CGSize.zero // Use any CGSize
self.layer.shadowColor =
UIColor.lightGray.cgColor
self.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0)
}
}
And apply this effect like below
email_textfield.applyCustomEffect()

UITextField shadow won't show

In my xib file, I have created a generic function through which I wanted to add a bottom border through implementing a shadow to those textfields
func setupTextField(textField: UITextField) {
textField.leftViewMode = UITextFieldViewMode.always
let imageView = UIImageView();
let image = UIImage(named: "calendar");
imageView.image = image;
imageView.frame = CGRect(x: 5, y: 8, width: 20, height: 20)
textField.addSubview(imageView)
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: textField.frame.height))
textField.leftView = paddingView
textField.borderStyle = .none
textField.layer.backgroundColor = UIColor.white.cgColor
textField.layer.masksToBounds = false
textField.layer.shadowColor = UIColor(hex: "#D8D8D8").cgColor
textField.layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
textField.layer.shadowOpacity = 1.0
textField.layer.shadowRadius = 0.0
}
And I have called this function from my awakeFromNib() method and as a result it added the shadow on my 2nd UITextField but not at the 1st one. Though from debug I can see that if there is no 2nd UITextField then this would draw a shadow on my 1st one.
How to overcome this problem?
For swift 4, swift 4.2, swift 5 Please refer below answer
Can give shadow to any UIView sub classes(imageview, label, textfield, textview etc)
extension UIView {
/* The color of the shadow. Defaults to opaque black. Colors created
* from patterns are currently NOT supported. Animatable. */
#IBInspectable var shadowColor: UIColor? {
set {
layer.shadowColor = newValue!.cgColor
}
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
else {
return nil
}
}
}
/* The opacity of the shadow. Defaults to 0.4 Specifying a value outside the
* [0,1] range will give undefined results. Animatable. */
#IBInspectable var shadowOpacity: Float {
set {
layer.shadowOpacity = newValue
}
get {
return layer.shadowOpacity
}
}
/* The shadow offset. Defaults to (1, 2). Animatable. */
#IBInspectable var shadowOffset: CGPoint {
set {
layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
}
get {
return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
}
}
/* The blur radius used to create the shadow. Defaults to 3. Animatable. */
#IBInspectable var shadowRadius: CGFloat {
set {
layer.shadowRadius = newValue
}
get {
return layer.shadowRadius
}
}
}
Textfield shadow
swift 4.2
textFieldDOB.backgroundColor = UIColor.white textFieldDOB.clipsToBounds = false
textFieldDOB.layer.shadowColor = UIColor.black.cgColor
textFieldDOB.layer.shadowOffset = CGSize.zero
textFieldDOB.layer.shadowOpacity = 0.3
textFieldDOB.layer.shadowRadius = 6
textFieldDOB.borderStyle = .none

Swift: UIButton Customization

I would like to move the code to customize UIButtons out of my viewcontroller classes as a best practice. The code I have below is to add a white border to UIButtons and I would like to easily call it on buttons throughout my project.
//White Border
let passwordBorder = CALayer()
let width = CGFloat(5.0)
passwordBorder.borderColor = UIColor.whiteColor().CGColor
passwordBorder.frame = CGRect(x: 0, y: 0, width: passwordField.frame.size.width, height: passwordField.frame.size.height)
passwordBorder.borderWidth = width
passwordField.layer.addSublayer(passwordBorder)
passwordField.layer.masksToBounds = true
How would I put this code into a helper function so I could call it easily?
I am new to coding and am having trouble with helper functions on anything UI. Thanks!
Take a look at Swift's Extensions. You could pretty easily do something like
extension UIButton {
func setPasswordBorderColor(borderColor: UIColor) {
//White Border
let passwordBorder = CALayer()
let width = CGFloat(5.0)
passwordBorder.borderColor = borderColor.CGColor
passwordBorder.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
passwordBorder.borderWidth = width
self.layer.addSublayer(passwordBorder)
self.layer.masksToBounds = true
}
}
import UIKit
//
#IBDesignable
class CustomBorderButton: UIButton {
#IBInspectable var cornerRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
layer.masksToBounds = cornerRadius > 0
}
}
#IBInspectable var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable var borderColor: UIColor? {
didSet {
layer.borderColor = borderColor?.CGColor
}
}
}
Without Code you can configure your button
Select Your button then Select Identity Inspector then add
"User Defined Runtime Attribute".See screen Shot for more details
Add CALayer+XibConfiguration.h & CALayer+XibConfiguration.m in your Project
for CALayer+XibConfiguration open this link & download CALayer+XibConfiguration
There are several ways by which you can achieve this like using category, subclassing UIButton, or create a function in a class (may be base class inherited by all other classes.), etc.
By using function you ca do
func cutomizeButton(frame : CGRect, title : String) -> UIButton {
let button : UIButton = UIButton(type: .Custom)
button.frame = frame
button.layer.borderWidth = 5.0
button.layer.borderColor = UIColor.whiteColor().CGColor;
button.layer.masksToBounds = true
button.titleLabel?.text = title;
//do other stuff
return button;
}
In helper class make method like
func customiseButton(button:UIButton){
//White Border
let passwordBorder = CALayer()
let width = CGFloat(5.0)
passwordBorder.borderColor = UIColor.whiteColor().CGColor
passwordBorder.frame = CGRect(x: 0, y: 0, width: button.frame.size.width, height: button.frame.size.height)
passwordBorder.borderWidth = width
button.layer.addSublayer(passwordBorder)
button.layer.masksToBounds = true
}
and in ViewController call this method as
HelperClass().customiseButton(passwordField)
You can try with this Extension for round button:
extension UIButton{
func roundCorners(corners:UIRectCorner, radius: CGFloat){
let borderLayer = CAShapeLayer()
borderLayer.frame = self.layer.bounds
borderLayer.strokeColor = UIColor.green.cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.lineWidth = 10.5
let path = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
borderLayer.path = path.cgPath
self.layer.addSublayer(borderLayer)
}
}

TableView rounded corners and shadow

I have a tableview with three rows. I am trying to make the table rows have rounded corners and also a shadow effect around the entire tableview. For some reason, I cannot make the tableview both have the rounded corners and shadow effect but I could do them separately if I comment out the code responsible for one of the features. Here is the code I am using:
//this is for shadow effect
tableView.backgroundColor = UIColor.clearColor()
tableView.layer.shadowColor = UIColor.darkGrayColor().CGColor
tableView.layer.shadowOffset = CGSize(width: 2.0, height: 2.0
tableView.layer.shadowOpacity = 1.0
tableView.layer.shadowRadius = 2
// This is for rounded corners
tableView.layer.cornerRadius = 10
tableView.layer.masksToBounds = true
You can add your table view to a container view and add drop shadow to that container view:
let containerView:UIView = UIView(frame:CGRect(x: 10, y: 100, width: 300, height: 400))
self.tableView = UITableView(frame: containerView.bounds), style: .Plain)
containerView.backgroundColor = UIColor.clearColor()
containerView.layer.shadowColor = UIColor.darkGrayColor().CGColor
containerView.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
// This is for rounded corners
self.tableView.layer.cornerRadius = 10
self.tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
containerView.addSubview(self.tableView)
Edit
Swift 3.0:
let containerView:UIView = UIView(frame:CGRect(x: 10, y: 100, width: 300, height: 400))
self.tableView = UITableView(frame: containerView.bounds, style: .plain)
containerView.backgroundColor = UIColor.clear
containerView.layer.shadowColor = UIColor.darkGray.cgColor
containerView.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
self.tableView.layer.cornerRadius = 10
self.tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
containerView.addSubview(self.tableView)
The RDC's answer is good, but for me the result didnt resolve my case, follow is my fix :
//for table view border
tableView.layer.borderColor = UIColor .grayColor().CGColor
tableView.layer.borderWidth = 1.0
//for shadow
let containerView:UIView = UIView(frame:self.tableView.frame)
//dont use clear color,fit blue color
containerView.backgroundColor = UIColor.blueColor()
//shadow view also need cornerRadius
containerView.layer.cornerRadius = 10
containerView.layer.shadowColor = UIColor.lightGrayColor().CGColor
containerView.layer.shadowOffset = CGSizeMake(-10, 10); //Left-Bottom shadow
//containerView.layer.shadowOffset = CGSizeMake(10, 10); //Right-Bottom shadow
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
//for rounded corners
tableView.layer.cornerRadius = 10
tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
self.view.addSubview(tableView)
i tried above solution but in my application tableview didSelectRowAt was not working.
use this Extension for UITabeleView
for corner
for shadow
//if u want shadow for all side use (shadowOffset = .zero)
extension UITableView {
func addCorner(){
self.layer.cornerRadius = 15
self.clipsToBounds = true
}
func addShadow(){
self.layer.shadowColor = UIColor.lightGray.cgColor
self.layer.shadowRadius = 5
self.layer.shadowOpacity = 0.5
self.layer.shadowOffset = .zero
self.layer.masksToBounds = false
}
}
How to use::
self.tableView.addCorner()
self.tableView.addShadow()
Thanks to #beyowulf
I have upgraded for me with Swift 2.2, to
set Border,
Rounded corner and
Drop shadow to the table view
//for table view border
tableView.layer.borderColor = UIColor .grayColor().CGColor
tableView.layer.borderWidth = 1.0
//for shadow
let containerView:UIView = UIView(frame:self.tableView.frame)
containerView.backgroundColor = UIColor.clearColor()
containerView.layer.shadowColor = UIColor.lightGrayColor().CGColor
containerView.layer.shadowOffset = CGSizeMake(-10, 10); //Left-Bottom shadow
//containerView.layer.shadowOffset = CGSizeMake(10, 10); //Right-Bottom shadow
containerView.layer.shadowOpacity = 1.0
containerView.layer.shadowRadius = 2
//for rounded corners
tableView.layer.cornerRadius = 10
tableView.layer.masksToBounds = true
self.view.addSubview(containerView)
containerView.addSubview(tableView)
result looks like

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.
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()
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.
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.
#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!
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
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
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
}
}
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
}
}
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)
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)
]
)
}
}
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()
}
}
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)
])
}
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)
}
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)
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
}()

Resources