UITextField: Bottom Border - ios

I am creating bottom bordered textfield. I am subclass of UITextField. Here it is:
#IBDesignable class LinedTextField: UITextField {
#IBInspectable var borderColor: UIColor = UIColor.whiteColor() {
didSet {
let border = CALayer()
border.borderColor = self.borderColor.CGColor
border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = borderWidth
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
}
#IBInspectable var borderWidth: CGFloat = 0.5 {
didSet {
let border = CALayer()
border.borderColor = self.borderColor.CGColor
border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = borderWidth
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
}
override init(frame : CGRect) {
super.init(frame : frame)
setup()
}
convenience init() {
self.init(frame:CGRectZero)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
func setup() {
let border = CALayer()
border.borderColor = self.borderColor.CGColor
border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width: self.frame.size.width, height: self.frame.size.height)
border.borderWidth = borderWidth
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
override func layoutSubviews() {
super.layoutSubviews()
}
Then in interface builder I set that 2 properties(border colour and border width) and everything looks good:
But when I run application on my real 5.5" device, it looks this way:
Border is not long as the text field. What's wrong here?

I think it's because the border frame need to be computed on layoutSubviews. Here is an example on how to do so (plus a simplification of your code):
Supported in Swift 3
#IBDesignable class UnderlinedTextField: UITextField {
let border = CALayer()
#IBInspectable var borderColor: UIColor = UIColor.white {
didSet {
setup()
}
}
#IBInspectable var borderWidth: CGFloat = 0.5 {
didSet {
setup()
}
}
override init(frame : CGRect) {
super.init(frame : frame)
setup()
}
convenience init() {
self.init(frame:CGRect.zero)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
func setup() {
border.borderColor = self.borderColor.cgColor
border.borderWidth = borderWidth
self.layer.addSublayer(border)
self.layer.masksToBounds = true
}
override func layoutSubviews() {
super.layoutSubviews()
border.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width: self.frame.size.width, height: self.frame.size.height)
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return editingRect(forBounds: bounds)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return editingRect(forBounds: bounds)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: 10, dy: 0)
}
}
EDIT:
I Added code for the text area. In this example, there is a 20px horizontal inset. There in more infos on editingRectForBounds (and its friends) in the Apple's doc: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextField_Class/#//apple_ref/occ/instm/UITextField/textRectForBounds:

import UIKit
#IBDesignable
class MyTextField: UITextField {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
func setupView(){
self.borderStyle = UITextBorderStyle.None
let border = CALayer()
let borderWidth: CGFloat = 2
border.borderColor = UIColor(red: 5/255, green: 84/255, blue: 115/255, alpha: 1.0).CGColor
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, self.frame.size.height)
border.borderWidth = borderWidth
self.layer.addSublayer(border)
}
}

let border = CALayer()
border.borderColor = UIColor.blackColor().CGColor
border.frame = CGRectMake(-30, textField.frame.size.height - 1.0, textField.frame.size.width*1.5 , 1.0)
border.borderWidth = 1.0
textField.layer.addSublayer(border)
textField.layer.masksToBounds = true

Related

UITextField with round corners and shadow but without border

I want to create a subclass of UITextField with custom rounded corners and a shadow around, here is what I tried:
class TextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
private func setupUI() {
font = .systemFont(ofSize: 14)
textColor = .black
layer.cornerRadius = 14.0
layer.borderWidth = 0.0
layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
layer.shadowOpacity = 1.0
layer.shadowRadius = 24.0
layer.shadowOffset = CGSize(width: 0, height: 8)
placeholder = "test"
}
}
However, there isn't any shadow that appears around my text field:
I tried playing with clipsToBounds and layer.masksToBounds properties, but with no success. What should I do?
Thank you for your help
You need to give it a background color.
And, if you really want a corner radius of 14, you'll probably want to change the default insets:
class TextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
private func setupUI() {
// add background color
backgroundColor = .white
font = .systemFont(ofSize: 14)
textColor = .black
layer.cornerRadius = 14.0
layer.borderWidth = 0.0
layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
layer.shadowOpacity = 1.0
layer.shadowRadius = 24.0
layer.shadowOffset = CGSize(width: 0, height: 8)
placeholder = "test"
}
// adjust as desired
var textPadding = UIEdgeInsets(
top: 10,
left: 20,
bottom: 10,
right: 20
)
override func textRect(forBounds bounds: CGRect) -> CGRect {
let rect = super.textRect(forBounds: bounds)
return rect.inset(by: textPadding)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
let rect = super.editingRect(forBounds: bounds)
return rect.inset(by: textPadding)
}
}
Result:
I made one extension for make rounded corners with shadow to any View like UIView,UIButton,UITextField etc.
extension UIView
{
func addCornerEffects(cornerRadius : CGFloat = 0, fillColor : UIColor = .white, shadowColor : UIColor = .clear, shadowOffset : CGSize, shadowOpacity : Float, shadowRadius : CGFloat, borderColor : UIColor, borderWidth : CGFloat)
{
self.layer.cornerRadius = cornerRadius
self.layer.shadowColor = shadowColor.cgColor
self.layer.shadowOffset = shadowOffset
self.layer.shadowRadius = shadowRadius
self.layer.shadowOpacity = shadowOpacity
self.layer.borderColor = borderColor.cgColor
self.layer.borderWidth = borderWidth
self.layer.backgroundColor = nil
self.layer.backgroundColor = fillColor.cgColor
}
}
You can use this in viewDidLoad in your ViewController like as below
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1)
{
self.txtFirstName.addCornerEffects(cornerRadius: 14, fillColor: .white, shadowColor: UIColor.black.withAlphaComponent(0.2), shadowOffset: CGSize(width: 0, height: 8), shadowOpacity: 1.0, shadowRadius: 25.0, borderColor: .clear, borderWidth: 0)
}
Here is output

Apply Shadow along with the gradient colour with custom class

I write the one custom class for gradient button, I want to apply shadow also for that.
I getting Gradient colour but I don't get the shadow.
Here I think I have issue with self.clipsToBounds = true
find my code with following.
class GradientButton: UIButton {
let gradientLayer = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
layer.cornerRadius = self.frame.size.height / 2.0
gradientLayer.locations = [0.0, 1.0]
// top-right to bottom-left
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
// we only add the layer once, here when called from init
layer.addSublayer(gradientLayer)
self.clipsToBounds = true
}
func setGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
gradientLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
applyShadow(shadoeclr: colorOne)
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}
func applyShadow(shadoeclr:UIColor){
layer.shadowColor = shadoeclr.cgColor
layer.shadowRadius = 5
layer.shadowOpacity = 0.5
layer.shadowOffset = CGSize(width: 0, height: 0)
}
}
try to use masksToBounds instead of clipsToBounds

UITextField Standard Style programmatically

When I create a UITextField using storyboard, it looks like the image below. However, when I create a UITextField programmatically it has absolutely no style. I know that I can apply custom styles to the text field, but is there an easy way to get this standard style when creating the text field programmatically?
Something like this:
let t = UITextField()
t.frame = CGRect(x: 10, y: 20, width: self.view.frame.width - 20, height: 40)
t.layer.cornerRadius = 5
t.layer.borderColor = UIColor.lightGray.cgColor
t.layer.borderWidth = 1
t.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
t.leftViewMode = .always
t.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
t.rightViewMode = .always
t.clearButtonMode = .whileEditing
self.view.addSubview(t)
EDIT:
Add this class below somewhere such that it is easily / globally accessible.
class StyledTextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.borderWidth = 1
self.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
self.leftViewMode = .always
self.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: t.frame.height))
self.rightViewMode = .always
self.clearButtonMode = .whileEditing
}
}
Then you can call this UITextField from where ever you want as follows
let t = StyledTextField()
t.frame = CGRect(x: 10, y: 20, width: self.view.frame.width - 20, height: 40)
self.view.addSubview(t)
EDIT 2:
Use UIEdgeInsets to get padding on all four sides.
class StyledTextField: UITextField {
let insetConstant = UIEdgeInsets(top: 4, left: 10, bottom: 4, right: 10)
override func textRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, insetConstant)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, insetConstant)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, insetConstant)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5
self.layer.borderColor = UIColor(white: 2/3, alpha: 0.5).cgColor
self.layer.borderWidth = 1
self.clearButtonMode = .whileEditing
self.keyboardType = UIKeyboardType.decimalPad
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You can add borderStyle as .roundedRect and use White background. Something like this:
class MyCustmUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.borderStyle = .roundedRect
self.backgroundColor = .white
}
}
You can create a subclass from UITextField to serve as your custom text field.
Following this, you need only to instantiate your custom class and then you're good to go.
Something like this:
class MyCustmUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5
self.layer.borderColor = UIColor.black
self.font = UIFont.systemFont(ofSize: 20)
self.adjustsFontSizeToFitWidth = true
// then add whatever styles you wish
}
}
From there all you need is to create a new instance of MyCustomUITextField

Animation origin iOS

I've been trying to create an animation that increases the height of a view without changing the origin (the top left and right edges stay in the same position)
import UIKit
class SampRect: UIView {
var res : CGRect?
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor(red: 0.91796875, green: 0.91796875, blue: 0.91796875, alpha: 1)
self.layer.cornerRadius = 5
let recognizer = UITapGestureRecognizer(target: self, action:#selector(SampRect.handleTap(_:)))
self.addGestureRecognizer(recognizer)
}
func handleTap(recognizer : UITapGestureRecognizer) {
let increaseSize = CABasicAnimation(keyPath: "bounds")
increaseSize.delegate = self
increaseSize.duration = 0.4
increaseSize.fromValue = NSValue(CGRect: frame)
res = CGRect(x: self.frame.minX, y: self.frame.minY, width: frame.width, height: self.frame.height + 10)
increaseSize.toValue = NSValue(CGRect: res!)
increaseSize.fillMode = kCAFillModeForwards
increaseSize.removedOnCompletion = false
layer.addAnimation(increaseSize, forKey: "bounds")
}
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
self.frame = res!
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
but the animation increase the size from the middle (push the top edge up and the bottom edge down)
what am I missing?
You can Try this.
let newheight:CGFloat = 100.0
UIView.animateWithDuration(0.5) {
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, newheight)
}

UIView rounded Corner - Swift 2.0?

Ill try to update some projects to Swift 2.0. I´ve got a View, with a rounded corner top left. Everything works fine in Swift < 1.2, but now, there is no rounded corner anymore.
No Warnings, no Errors, just no rounded corner.
This is how it works in Swift < 1.2.
let maskPath = UIBezierPath(roundedRect: contentView.bounds,byRoundingCorners: .TopLeft, cornerRadii: CGSize(width: 10.0, height: 10.0))
let maskLayer = CAShapeLayer(layer: maskPath)
maskLayer.frame = contentView.bounds
maskLayer.path = maskPath.CGPath
contentView.layer.mask = maskLayer
Anyone know whats wrong here? Ill dont find any changes in the documentation.
There's nothing wrong with this piece of code in Swift 2.0–2.1. Are you sure there isn't something else before or after this code snippet, that's affecting your view?
Here's a quick Playground with your code:
Swift 4.0 - 5.0
You can use a simple class I have created to create a UIView and add rounded corners directly from Storyboard
You can find the class here
import Foundation
import UIKit
#IBDesignable class SwiftRoundView: UIView {
#IBInspectable fileprivate var borderColor: UIColor = .white { didSet { self.layer.borderColor = self.borderColor.cgColor } }
#IBInspectable fileprivate var borderWidth: CGFloat = 0.00 { didSet { self.layer.borderWidth = self.borderWidth } }
#IBInspectable fileprivate var cornerRadius: CGFloat = 0.00 { didSet { self.layer.cornerRadius = self.cornerRadius } }
init(x: CGFloat = 0.0, y: CGFloat = 0.0, width: CGFloat, height: CGFloat, cornerRadius: CGFloat = 0.0, borderWidth: CGFloat = 0.0, borderColor: UIColor = .white) {
self.cornerRadius = cornerRadius
self.borderWidth = borderWidth
self.borderColor = borderColor
super.init(frame: CGRect(x: x, y: y, width: width, height: height))
setupView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
fileprivate func setupView() {
self.layer.cornerRadius = cornerRadius
self.layer.borderWidth = borderWidth
self.layer.borderColor = borderColor.cgColor
self.clipsToBounds = true
}
}

Resources