Cant change custom UITextField border color - ios

I am trying to make a nice textField but it didn't work. So my problem is when i begin edit textfield i need to change border color to another, but when it happens my custom border going to default rect. What i want it's just change color of bottom border.
func textFieldDidBeginEditing(_ textField: UITextField) {
nameField.borderStyle = UITextBorderStyle.none
nameField.layer.borderWidth = 2.0
nameField.layer.borderColor = UIColor.red.cgColor
nameField.layer.masksToBounds = true
print("lol")
}
public func testField() {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = lightBlue
border.frame = CGRect(x: 0, y: nameField.frame.size.height - width, width: nameField.frame.size.width, height: nameField.frame.size.height)
border.borderWidth = width
nameField.layer.addSublayer(border)
nameField.layer.masks[ToBounds = true
}

Here is a solution. I have subclassed UITextField and overrided layoutSubviews func with checking if it is firstResponder (means cursor is there) or not and setting corresponding color.
Swift (3.0):
class TextField: UITextField {
lazy var bottomBorder: CALayer = {
let border = CALayer();
border.borderColor = UIColor.white.cgColor;
border.borderWidth = 1;
return border
}()
override func awakeFromNib() {
super.awakeFromNib()
borderStyle = .none;
layer.addSublayer(bottomBorder);
}
override func layoutSubviews() {
super.layoutSubviews();
let borderColor = isFirstResponder ? UIColor.blue : UIColor.white;
bottomBorder.borderColor = borderColor.cgColor;
bottomBorder.frame = CGRect(x: 0, y: layer.frame.size.height - 1, width: layer.frame.size.width, height: 1)
}
}
Objective-C
#interface TextField ()
#property (nonatomic, strong) CALayer *bottomBorder;
#end
#implementation TextField
- (void)awakeFromNib {
[super awakeFromNib];
[self.layer addSublayer:self.bottomBorder];
}
- (void)layoutSubviews {
[super layoutSubviews];
UIColor *borderColor = self.isFirstResponder ? [UIColor blueColor] : [UIColor whiteColor];
self.bottomBorder.borderColor = borderColor.CGColor;
self.bottomBorder.frame = CGRectMake(0, self.layer.frame.size.height - 1, self.layer.frame.size.width, 1);
}
- (CALayer *)bottomBorder {
if (!_bottomBorder) {
_bottomBorder = [CALayer layer];
_bottomBorder.borderColor = [UIColor whiteColor].CGColor;
_bottomBorder.borderWidth = 1;
}
return _bottomBorder;
}
#end

Make your border
let border = CALayer()
Global and the just change its borderColor in textFieldDidBeginEditing
func textFieldDidBeginEditing(_ textField: UITextField) {
border.borderColor = UIColor.red.cgColor
}
Hope this helps.

Try to add this line of code in your func textFieldDidBeginEditing(_ textField: UITextField) method, this will remove your custom layer and you can see the change done.
if (nameField.layer.sublayers?.count)! > 0{
nameField.layer.sublayers?[0].removeFromSuperlayer()
}
Hope this helps.

Use this piece of code
func textFieldDidBeginEditing(_textField: UITextField) {
nameField.layer.sublayers![1].borderColor = UIColor.redColor().CGColor
}
func testField() {
nameField.layer.sublayers![0].hidden = true
let border = CALayer()
border.frame = CGRectMake(0, nameField.frame.size.height - 2, nameField.frame.size.width, 20)
border.borderColor = UIColor.blueColor().CGColor
border.borderWidth = 2
nameField.layer.addSublayer(border)
}

You need to add additional sublayer to border of textfield so that you can assign any of the color.
let border = CALayer()
let width = CGFloat(1.0)
border.borderColor = UIColor(red: 188/255, green: 189/255, blue: 192/255 , alpha: 1).CGColor
border.frame = CGRect(x: 0, y: textField.frame.size.height - width, width: textField.frame.size.width, height: textField.frame.size.height)
border.borderWidth = width
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true

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()

Change the border color of uitextfield

I added bottom border to UITextField this way:
let bottomLine = CALayer()
bottomLine.frame = CGRectMake(0.0, self.frame.height, self.frame.width, CGFloat(borderWidth))
bottomLine.backgroundColor = borderColor.CGColor
self.borderStyle = UITextBorderStyle.None
self.layer.addSublayer(bottomLine)
How can I change the border color of this bottom line when UITextField call textFieldDidBeginEditing() and then change back color to default when it calls textFieldDidEndEditing()
I'm using a custom class of UITextField
Try just re-adding the layer with the default color in the textFieldDidEndEditing method, like so:
func textFieldDidBeginEditing(_ textField: UITextField) {
let bottomLine = CALayer()
bottomLine.frame = CGRectMake(0.0, self.frame.height, self.frame.width, CGFloat(borderWidth))
bottomLine.backgroundColor = borderColor.CGColor
self.borderStyle = UITextBorderStyle.None
self.layer.addSublayer(bottomLine)
}
func textFieldDidEndEditing(_ textField: UITextField) {
let bottomLine = CALayer()
bottomLine.frame = CGRectMake(0.0, self.frame.height, self.frame.width, CGFloat(borderWidth))
bottomLine.backgroundColor = defaultColor.CGColor
self.borderStyle = UITextBorderStyle.None
self.layer.addSublayer(bottomLine)
}
This worked for me
Take Action methods of textfield as editing did begin and editing did end
This will work fine, I have tested it
#IBAction func didbegin(_ sender: AnyObject) {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.green.cgColor
border.frame = CGRect(x: 0, y: txtfield.frame.size.height - width, width: txtfield.frame.size.width, height: txtfield.frame.size.height)
border.borderWidth = width
txtfield.layer.addSublayer(border)
txtfield.layer.masksToBounds = true
}
#IBAction func endediting(_ sender: AnyObject) {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.black.cgColor
border.frame = CGRect(x: 0, y: txtfield.frame.size.height - width, width: txtfield.frame.size.width, height: txtfield.frame.size.height)
border.borderWidth = width
txtfield.layer.addSublayer(border)
txtfield.layer.masksToBounds = true
}
Hope this thing helps you.
func viewWillAppear(_ animated: Bool) {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.white.cgColor
border.frame = CGRect(x: 0, y: yourTextFeild.frame.size.height - width, width: yourTextFeild.frame.size.width, height: yourTextFeild.frame.size.height)
border.borderWidth = width
yourTextFeild.layer.addSublayer(border)
yourTextFeild.layer.masksToBounds = true
}
//Mark Textfield Delegate
func textFieldDidBeginEditing(_ textField: UITextField) {
for layer in textField.layer.sublayers!{
layer.borderColor = UIColor.green.cgColor
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
for layer in textField.layer.sublayers!{
layer.borderColor = UIColor.white.cgColor
}
}

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)
}
}

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
}()

iOS add / remove shadow from a view

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
})
}
}

Resources