I've a custom UITabBar. Its bar has a simple but customised shape: its height is bigger then default one, has rounded corners and (important) a shadow layer on the top.
The result is this:
Now I've to add an element that shows the selected section on the top of the bar, to achieve this:
The problem is that no matter the way I choose to add this element (add a subview to the bar or add a new sublayer) but the new element will always be drawn outside the corners. I suppose this is because I can't enable the clipping mask (if I enable the clipping mask I'll kill the shadow and also, more important, the bezierpath)
Do you have any tips for this?
Basically, the goal should be:
have an element that moves horizontally (animated) but cannot be drawn outside the parent (the tabbar)
Actually, the code to draw the custom tabBar is:
class CustomTabBar: UITabBar {
/// The layer that defines the custom shape
private var shapeLayer: CALayer?
/// The radius for the border of the bar
var borderRadius: CGFloat = 0
override func layoutSubviews() {
super.layoutSubviews()
// aspect and shadow
isTranslucent = false
backgroundColor = UIColor.white
tintColor = AZTheme.PaletteColor.primaryColor
shadowImage = nil
layer.masksToBounds = false
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.1
layer.shadowOffset = CGSize(width: 0, height: -1)
layer.shadowRadius = 10
}
override func draw(_ rect: CGRect) {
drawShape()
}
/// Draw and apply the custom shape to the bar
func drawShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()
shapeLayer.fillColor = AZTheme.tabBarControllerBackgroundColor.cgColor
if let oldShapeLayer = self.shapeLayer {
self.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
} else {
self.layer.insertSublayer(shapeLayer, at: 0)
}
self.shapeLayer = shapeLayer
}
}
// MARK: - Private functions
extension CustomTabBar {
/// Return the custom shape for the bar
internal func createPath() -> CGPath {
let height: CGFloat = self.frame.height
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addArc(withCenter: CGPoint(x: borderRadius, y: 0), radius: borderRadius, startAngle: CGFloat.pi, endAngle: CGFloat.pi * (3/2), clockwise: true)
path.addLine(to: CGPoint(x: frame.width - borderRadius, y: -borderRadius))
path.addArc(withCenter: CGPoint(x: frame.width - borderRadius, y: 0), radius: borderRadius, startAngle: CGFloat.pi * (3/2), endAngle: 0, clockwise: true)
path.addLine(to: CGPoint(x: frame.width, y: height))
path.addLine(to: CGPoint(x: 0, y: height))
path.close()
return path.cgPath
}
}
I solved splitting the owner of custom shape from the owner of the shadow in 2 different views. So I'm using 3 views achieve the goal.
CustomTabBar: has default size and casts shadow with offset.
|
└ SelectorContainer: is a view with custom shape (BezierPath) that is
positioned on the top of the TabBar to graphically "extend" the view
and have the feeling of a bigger TabBar. It has rounded corners on
the top-right, top-left margin. MaskToBounds enabled.
|
└ Selector: simple view that change the its origin through animation.
See the result here
The code:
class CustomTabBar: UITabBar {
/// The corner radius value for the top-left, top-right corners of the TabBar
var borderRadius: CGFloat = 0
/// Who is containing the selector. Is a subview of the TabBar.
private var selectorParent: UIView?
/// Who moves itself following the current section. Is a subview of ```selectorParent```.
private var selector: UIView?
/// The height of the ```selector```
private var selectorHeight: CGFloat = 5
/// The number of sections handled by the TabBarController.
private var numberOfSections: Int = 0
override func layoutSubviews() {
super.layoutSubviews()
isTranslucent = false
backgroundColor = UIColor.white
tintColor = AZTheme.PaletteColor.primaryColor
shadowImage = nil
layer.masksToBounds = false
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.1
layer.shadowOffset = CGSize(width: 0, height: -1)
layer.shadowRadius = 10
}
}
// MARK: - Private functions
extension CustomTabBar {
/// Create the selector element on the top of the TabBar
func setupSelectorView(numberOfSections: Int) {
self.numberOfSections = numberOfSections
// delete previous subviews (if exist)
if let selectorContainer = self.selectorParent {
selectorContainer.removeFromSuperview()
self.selector?.removeFromSuperview()
self.selectorParent = nil
self.selector = nil
}
// SELECTOR CONTAINER
let selectorContainerRect: CGRect = CGRect(x: 0,
y: -borderRadius,
width: frame.width,
height: borderRadius)
let selectorContainer = UIView(frame: selectorContainerRect)
selectorContainer.backgroundColor = UIColor.white
selectorContainer.AZ_roundCorners([.topLeft, .topRight], radius: borderRadius)
selectorContainer.layer.masksToBounds = true
self.addSubview(selectorContainer)
// SELECTOR
let selectorRect: CGRect = CGRect(x: 0,
y: 0,
width: selectorContainer.frame.width / CGFloat(numberOfSections),
height: selectorHeight)
let selector = UIView(frame: selectorRect)
selector.backgroundColor = AZTheme.PaletteColor.primaryColor
selectorContainer.addSubview(selector)
// add views to hierarchy
self.selectorParent = selectorContainer
self.selector = selector
}
/// Animate the position of the selector passing the index of the new section
func animateSelectorTo(sectionIndex: Int) {
guard let selectorContainer = self.selectorParent, let selector = self.selector else { return }
selector.layer.removeAllAnimations()
let sectionWidth: CGFloat = selectorContainer.frame.width / CGFloat(numberOfSections)
let newCoord = CGPoint(x: sectionWidth * CGFloat(sectionIndex), y: selector.frame.origin.y)
UIView.animate(withDuration: 0.25, delay: 0, options: UIView.AnimationOptions.curveEaseOut, animations: { [weak self] in
self?.selector?.frame.origin = newCoord
}, completion: nil)
}
}
Related
I have a view that needs to be displayed with a slanted corner on one side. I've already done it when the view has a background color like this:
But I also need it to be displayed with a clear background. After setting its background to clear and adding a border to it this is the output:
Here is the code for the custom view that I'm using to create the diagonal corner:
class PointedView: UIImageView {
#IBInspectable var borderColor: UIColor = UIColor.clear {
didSet {
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable var borderWidth: CGFloat = 0 {
didSet {
layer.borderWidth = borderWidth
}
}
#IBInspectable
/// Percentage of the slant based on the width
var slopeFactor: CGFloat = 15 {
didSet {
updatePath()
}
}
private let shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 0
// with masks, the color of the shape layer doesn’t matter;
// it only uses the alpha channel; the color of the view is
// dictate by its background color
shapeLayer.fillColor = UIColor.white.cgColor
return shapeLayer
}()
override func layoutSubviews() {
super.layoutSubviews()
updatePath()
}
private func updatePath() {
let path = UIBezierPath()
// Start from x = 0 but the mid point of y of the view
path.move(to: CGPoint(x: 0, y: bounds.midY*2))
// Create the top slanting line
path.addLine(to: CGPoint(x: bounds.minX, y: bounds.minY))
// Straight line from end of slant to the end of the view
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
// Straight line to come down to the bottom, perpendicular to view
path.addLine(to: CGPoint(x: bounds.maxX, y: ((bounds.maxY*3)/4) + 20))
// Go back to the slant end position but from the bottom
path.addLine(to: CGPoint(x: (bounds.maxX*3)/4, y: bounds.maxY))
// Close path back to where you started
path.close()
shapeLayer.path = path.cgPath
layer.mask = shapeLayer
}
}
Is there any possible solution to this?
class PointedView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createBezierPath().cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.blue.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.position = CGPoint(x: 10, y: 10)
self.layer.addSublayer(shapeLayer)
}
func createBezierPath() -> UIBezierPath {
let path = UIBezierPath()
// Start from x = 0 but the mid point of y of the view
path.move(to: CGPoint(x: 0, y: bounds.midY*2))
// Create the top slanting line
path.addLine(to: CGPoint(x: bounds.minX, y: bounds.minY))
// Straight line from end of slant to the end of the view
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
// Straight line to come down to the bottom, perpendicular to view
path.addLine(to: CGPoint(x: bounds.maxX, y: ((bounds.maxY*3)/4) + 20))
// Go back to the slant end position but from the bottom
path.addLine(to: CGPoint(x: (bounds.maxX*3)/4, y: bounds.maxY))
// Close path back to where you started
path.close() // draws the final line to close the path
return path
}
}
Managed to solve it by drawing another CAShapeLayer() following the same path as the original shape.
let borderLayer = CAShapeLayer()
borderLayer.path = path.cgPath
borderLayer.lineWidth = 2
borderLayer.strokeColor = borderColor.cgColor
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.frame = bounds
layer.addSublayer(borderLayer)
if you are using StoryBoard with #IBInspectable you can try like thisenter image description here
Please use this method
func roundCorners(corners: UIRectCorner = .allCorners, radius: CGFloat = 0.0, borderColor: UIColor = .clear, borderWidth: CGFloat = 0.0, clipToBonds: Bool = true) {
clipsToBounds = clipToBonds
layer.cornerRadius = radius
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor
if corners.contains(.allCorners){
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
return
}
var maskedCorners = CACornerMask()
if corners.contains(.topLeft) { maskedCorners.insert(.layerMinXMinYCorner) }
if corners.contains(.topRight) { maskedCorners.insert(.layerMaxXMinYCorner) }
if corners.contains(.bottomLeft) { maskedCorners.insert(.layerMinXMaxYCorner) }
if corners.contains(.bottomRight) { maskedCorners.insert(.layerMaxXMaxYCorner) }
layer.maskedCorners = maskedCorners
}
and by using your UIVIEW
View.roundCorners(corners: [.topLeft, .bottomLeft], radius: 20, borderColor: .clear, borderWidth: 0, clipToBonds: true)
here is a situation.
I've created a storyboard and UIViewController. To UIViewController I've added UITableView. To UITableView I've registered custom TableViewCell in which I need to add a rounded image and drop shadow from it.
I've created UIView and added to it UIImageView. For UIView I've created file with the following code:
class drawView: UIView {
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else {
return
}
self.drawCircle(context)
}
private func drawCircle(_ context: CGContext){
context.setStrokeColor(UIColor.black.cgColor)
let newMask = CAShapeLayer()
let circlePath = UIBezierPath(ovalIn: .init(x: 0, y: 0, width: 50, height: 50))
newMask.path = circlePath.cgPath
self.layer.mask = newMask //if I comment this line then the shadows works properly, if not, there is no shadows
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOpacity = 0.5
self.layer.shadowOffset = .init(width: 10, height: -10)
self.layer.shadowRadius = 2
}
}
How can I make rounded image and rounded shadow from it in the table row?
Thanks in advance for help.
I made some extensions, check this:
extension UIView {
/// Apply corder radius to the view
/// - parameter radius: The corder radius value applied to view. Default value: 4
func makeRoundCorner(withRadius radius: CGFloat = 4) {
clipsToBounds = true
layer.cornerRadius = radius
}
/// Apply shadow to the view
/// - parameter offset: The offset (in points) of the layer’s shadow. Default value: CGSize(width: 0, height: 2)
/// - parameter opacity: The opacity of the layer’s shadow. Default value: 0.2
/// - parameter radius: The blur radius (in points) used to render the layer’s shadow. Default value: 4
/// - parameter color: The color of the layer’s shadow. Default value: opaque black
func makeShadow(offset: CGSize = CGSize(width: 0, height: 2),
opacity: Float = 0.2,
radius: CGFloat = 4,
color: UIColor = UIColor.black) {
let layer = self.layer
layer.shadowColor = color.cgColor
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.shadowOpacity = opacity
clipsToBounds = false
}
}
How to use and the output
let image = UIImageView(image: UIImage(named: "test_icon"))
image.backgroundColor = .red
image.makeRoundCorner(withRadius: 20)
image.makeShadow(offset: CGSize(width: 1, height: 1), opacity: 1, radius: 4, color: .black)
I have an icon that I programmatically display.
How can I display a solid, colored disk behind the icon, at the same screen position?
Icon is opaque.
I will sometimes programmatically change screen position and disk's diameter and color.
Here's how I programmatically display the icon now.............
DispatchQueue.main.async
{
ViewController.wrist_band_UIImageView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
}
UPDATE #1 for D.Mika below...
UPDATE #2 for D.Mika below...
import UIKit
import Foundation
class ViewController: UIViewController
{
static var circleView: UIView!
static let wrist_band_UIImageView: UIImageView = {
let theImageView = UIImageView()
theImageView.image = UIImage( systemName: "applewatch" )
theImageView.translatesAutoresizingMaskIntoConstraints = false
return theImageView
}()
override func viewDidLoad()
{
super.viewDidLoad()
view.addSubview( ViewController.wrist_band_UIImageView )
// Init disk image:
ViewController.circleView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
ViewController.circleView.backgroundColor = .red
ViewController.circleView.layer.cornerRadius = view.bounds.size.height / 2.0
ViewController.circleView.clipsToBounds = true
// Add view to view hierarchy below image view
ViewController.circleView.insertSubview(view, belowSubview: ViewController.wrist_band_UIImageView)
App_class.display_single_wearable()
}
}
class App_class
{
static var is_communication_established = false
static var total_packets = 0
static func display_single_wearable()
{
ViewController.wrist_band_UIImageView.frame = CGRect(x: 0, y: 0,
width: 100, height: 100)
ViewController.circleView.frame = CGRect( x: 0,
y: 0,
width: 100,
height: 100)
ViewController.circleView.layer.cornerRadius = 100
}
static func process_location_xy(text_location_xyz: String)
{}
} // App_class
You can display a colored circle using the following view:
circleView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
circleView.backgroundColor = .red
circleView.layer.cornerRadius = view.bounds.size.height / 2.0
circleView.clipsToBounds = true
// Add view to view hierarchy below image view
view.insertSubview(circleView, belowSubview: wrist_band_UIImageView)
You can change it's position and size by applying a new frame. But you have to change the layer's cornerRadius accordingly.
This is a simple example in a playground:
Edit:
I've modified the sample code to add the view the view hierarchy.
BUT, you still need to adjust the circle's frame, when you modify the image view's frame. (and the cornerRadius accordingly). For example
DispatchQueue.main.async
{
ViewController.wrist_band_UIImageView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
circleView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
circleView.layer.cornerRadius = App_class.screen_width
}
And you need to add a variable to the viewController holding the reference to the circle view, like:
var circleView: UIView!
The following answer works.
The answers from d.mika above did not work. Plus, he was insulting. ;-)
// Show red circle
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 200, y: 400), radius: CGFloat(40), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
// Change the fill color
shapeLayer.fillColor = UIColor.red.cgColor
// You can change the stroke color
shapeLayer.strokeColor = UIColor.red.cgColor
// You can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)
I'm trying to make this corner radius image...it's not exactly the same shape of the image..any easy answer instead of trying random numbers of width and height ?
thanks alot
let rectShape = CAShapeLayer()
rectShape.bounds = self.mainImg.frame
rectShape.position = self.mainImg.center
rectShape.path = UIBezierPath(roundedRect: self.mainImg.bounds, byRoundingCorners: [.bottomLeft , .bottomRight ], cornerRadii: CGSize(width: 50, height: 4)).cgPath
You can use QuadCurve to get the design you want.
Here is a Swift #IBDesignable class that lets you specify the image and the "height" of the rounding in Storyboard / Interface Builder:
#IBDesignable
class RoundedBottomImageView: UIView {
var imageView: UIImageView!
#IBInspectable var image: UIImage? {
didSet { self.imageView.image = image }
}
#IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
doMyInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
doMyInit()
}
func doMyInit() {
imageView = UIImageView()
imageView.backgroundColor = UIColor.red
imageView.contentMode = UIViewContentMode.scaleAspectFill
addSubview(imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = self.bounds
let rect = self.bounds
let y:CGFloat = rect.size.height - roundingValue
let curveTo:CGFloat = rect.size.height + roundingValue
let myBezier = UIBezierPath()
myBezier.move(to: CGPoint(x: 0, y: y))
myBezier.addQuadCurve(to: CGPoint(x: rect.width, y: y), controlPoint: CGPoint(x: rect.width / 2, y: curveTo))
myBezier.addLine(to: CGPoint(x: rect.width, y: 0))
myBezier.addLine(to: CGPoint(x: 0, y: 0))
myBezier.close()
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}
Result with 300 x 200 image view, rounding set to 40:
Edit - (3.5 years later)...
To answer #MiteshDobareeya comment, we can switch the rounded edge from Bottom to Top by transforming the bezier path:
let c = CGAffineTransform(scaleX: 1, y: -1).concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
It's been quite a while since this answer was originally posted, so a few changes:
subclass UIImageView directly - no need to make it a UIView with an embedded UIImageView
add a Bool roundTop var
if set to False (the default), we round the Bottom
if set to True, we round the Top
re-order and "name" our path points for clarity
So, the basic principle:
We create a UIBezierPath and:
move to pt1
add a line to pt2
add a line to pt3
add a quad-curve to pt4 with controlPoint
close the path
use that path for a CAShapeLayer mask
the result:
If we want to round the Top, after closing the path we can apply apply a scale transform using -1 as the y value to vertically mirror it. Because that transform mirror it at "y-zero" we also apply a translate transform to move it back down into place.
That gives us:
Here's the updated class:
#IBDesignable
class RoundedTopBottomImageView: UIImageView {
#IBInspectable var roundingValue: CGFloat = 0.0 {
didSet {
self.setNeedsLayout()
}
}
#IBInspectable var roundTop: Bool = false {
didSet {
self.setNeedsLayout()
}
}
override func layoutSubviews() {
super.layoutSubviews()
let r = bounds
let myBezier = UIBezierPath()
let pt1: CGPoint = CGPoint(x: r.minX, y: r.minY)
let pt2: CGPoint = CGPoint(x: r.maxX, y: r.minY)
let pt3: CGPoint = CGPoint(x: r.maxX, y: r.maxY - roundingValue)
let pt4: CGPoint = CGPoint(x: r.minX, y: r.maxY - roundingValue)
let controlPoint: CGPoint = CGPoint(x: r.midX, y: r.maxY + roundingValue)
myBezier.move(to: pt1)
myBezier.addLine(to: pt2)
myBezier.addLine(to: pt3)
myBezier.addQuadCurve(to: pt4, controlPoint: controlPoint)
myBezier.close()
if roundTop {
// if we want to round the Top instead of the bottom,
// flip the path vertically
let c = CGAffineTransform(scaleX: 1, y: -1) //.concatenating(CGAffineTransform(translationX: 0, y: bounds.size.height))
myBezier.apply(c)
}
let maskForPath = CAShapeLayer()
maskForPath.path = myBezier.cgPath
layer.mask = maskForPath
}
}
You can try with UIView extension. as
extension UIView {
func setBottomCurve(){
let offset = CGFloat(self.frame.size.height + self.frame.size.height/1.8)
let bounds = self.bounds
let rectBounds = CGRect(x: bounds.origin.x,
y: bounds.origin.y ,
width: bounds.size.width,
height: bounds.size.height / 2)
let rectPath = UIBezierPath(rect: rectBounds)
let ovalBounds = CGRect(x: bounds.origin.x - offset / 2,
y: bounds.origin.y ,
width: bounds.size.width + offset,
height: bounds.size.height)
let ovalPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = rectPath.cgPath
self.layer.mask = maskLayer
}
}
& use it in viewWillAppear like methods where you can get actual frame of UIImageView.
Usage:
override func viewWillAppear(_ animated: Bool) {
//use it in viewWillAppear like methods where you can get actual frame of UIImageView
myImageView.setBottomCurve()
}
I am new to swift. Your help will be really appreciated.
I have two textfields in my application. How would I create same UI as given in the pic below.
I want to create textfields with only one below border as given in the screenshot.
https://www.dropbox.com/s/wlizis5zybsvnfz/File%202017-04-04%2C%201%2052%2024%20PM.jpeg?dl=0
#IBOutlet var textField: UITextField! {
didSet {
let border = CALayer()
let width: CGFloat = 1 // this manipulates the border's width
border.borderColor = UIColor.darkGray.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
}
}
Create a subclass of UITextField so you can reuse this component across multiple views without have to re implement the drawing code. Expose various properties via #IBDesignable and #IBInspectable and you can have control over color and thickness in the story board. Also - implement a "redraw" on by overriding layoutSubviews so the border will adjust if you are using auto layout and there is an orientation or perhaps constraint based animation. That all said - effectively your subclass could look like this:
import UIKit
class Field: UITextField {
private let border = CAShapeLayer()
#IBInspectable var color: UIColor = UIColor.blue {
didSet {
border.strokeColor = color.cgColor
}
}
#IBInspectable var thickness: CGFloat = 1.0 {
didSet {
border.lineWidth = thickness
}
}
override func draw(_ rect: CGRect) {
self.borderStyle = .none
let from = CGPoint(x: 0, y: rect.height)
let here = CGPoint(x: rect.width, y: rect.height)
let path = borderPath(start: from, end: here).cgPath
border.path = path
border.strokeColor = color.cgColor
border.lineWidth = thickness
border.fillColor = nil
layer.addSublayer(border)
}
override func layoutSubviews() {
super.layoutSubviews()
let from = CGPoint(x: 0, y: bounds.height)
let here = CGPoint(x: bounds.width, y: bounds.height)
border.path = borderPath(start: from, end: here).cgPath
}
private func borderPath(start: CGPoint, end: CGPoint) -> UIBezierPath {
let path = UIBezierPath()
path.move(to: start)
path.addLine(to: end)
return path
}
}
Then when you add a text field view to your story board - update the class in the Identity Inspector to use this subclass, Field - and then in the attributes inspector, you can set color and thickness.
Add border at Bottom in UITextField call below function:
func setTextFieldBorder(_ dimension: CGRect) -> CALayer {
let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: dimension.size.height - width, width: dimension.size.width, height: dimension.size.height)
border.borderWidth = width
return border
}
How to set UITextField border in textField below sample code for that:
txtDemo.layer.addSublayer(setTextFieldBorder(txtDemo.frame))
txtDemo.layer.masksToBounds = true
Where txtDemo is IBOutlet of UITextField.