How to add with to border UITextField Swift when when create Rounded corners - ios

I want to create a rounded corner "Oval shape" UITextField. I have a problem with the inner border is not rounded and give strange log to the UITextField when the background of the UITextField same as the view
How border looks:
Image from the MockAUp what I want to achieve:
Swift code:
txtfEmail.layer.cornerRadius = 26
txtfEmail.clipsToBounds = true
txtfEmail.attributedPlaceholder = NSAttributedString(string: "Email",
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white.withAlphaComponent(0.5)])
email UITextfield inspectere

One approach would be to create a custom UIView class with an embedded text field.
Here's an example, using #IBInspectable and #IBDesignable to let you see it during Storyboard design:
import UIKit
#IBDesignable
class RoundedTextField: UIView {
#IBInspectable var placeholder: String = "" {
didSet {
textField.attributedPlaceholder = NSAttributedString(string: placeholder,
attributes: [NSAttributedString.Key.foregroundColor: UIColor.white.withAlphaComponent(0.5)])
}
}
let textField: UITextField = {
let v = UITextField()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override func prepareForInterfaceBuilder() {
commonInit()
}
func commonInit() -> Void {
layer.borderColor = UIColor.white.cgColor
layer.borderWidth = 2
layer.masksToBounds = true
addSubview(textField)
NSLayoutConstraint.activate([
textField.topAnchor.constraint(equalTo: topAnchor, constant: 12.0),
textField.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12.0),
textField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20.0),
textField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20.0),
])
}
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = bounds.size.height * 0.5
}
}
Result in Storyboard / Interface Builder:

You should create the rounded border like this:
txtfEmail.layer.cornerRadius = txtfEmail.height / 2
txtfEmail.layer.borderWidth = 1
txtfEmail.layer.borderColor = UIColor.black.cgColor
Looks like the border is set to the view under the text field

try this it works for me
open storyboard
drag and drop textfield
ctrl click and create an outlet in view controller and name it lets say emailfield
then write this code
#iboultet weak var emailfield: uitextfield!{
didset{
emailfield.layer.masktobounds = true
emailfield.layer.cornerradius = 26
emailfield.layer.borderwidth = 1
emailfield.backgroundcolor = whatever color you want

Related

How to get UITextView to anchor to the right of UICollectionViewCell?

I have UITextView that I want to anchor to the right of my UICollectionViewCell. I apply the following constraint: textView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
But it DOES NOT anchor all the way to the right. I then apply the following constraint but this time: textView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true and it DOES anchor all the way to the left. Why might this be?
https://imgur.com/a/uykWLw5
Here is my ChatMessageCell.
import UIKit
class ChatMessageCell: UICollectionViewCell {
let textView: UITextView = {
let tv = UITextView()
tv.text = "Some Text"
tv.font = UIFont.systemFont(ofSize: 16)
tv.translatesAutoresizingMaskIntoConstraints = false
return tv
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(textView)
textView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
textView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
textView.widthAnchor.constraint(equalToConstant: 200).isActive = true
textView.heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Your textView would be left-aligned. If you want your text view to remain with a width of 200 and appear to sit on the right you need to add: textView.textAlignment = .right
Also, I belive it's best to use leading and trailing constraints

UIViewController with custom UIView (that includes a button) doesn't recognize taps

When trying to load a custom UIView (BaseHeader.swift) that contains a UIButton into a UIViewController (ViewController.swift) programmatically, the taps on the button are not recognized.
If I extract the code within the custom UIView and paste it directly into the UIViewController, all taps are recognized and working as expected. What am I missing?
At first, I thought it was a problem with not defining a frame size for the UIView after it gets instantiated. I thought that there might be no "hit box" for the button despite it being displayed as intended. After giving the view a frame I still had no luck and tried various other things after googling about for awhile.
The view loads but button taps are not recognized -- see image
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.title = "Authentication"
}
override func loadView() {
super.loadView()
let header = BaseHeader()
header.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(header)
NSLayoutConstraint.activate([
header.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
header.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
header.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: -10),
])
}
}
BaseHeader.swift
import UIKit
class BaseHeader: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setupView() {
self.isUserInteractionEnabled = true
let avenirFont = UIFont(name: "Avenir", size: 40)
let lightAvenirTitle = avenirFont?.light
let title = UILabel()
title.text = "Title"
title.font = lightAvenirTitle
title.textColor = .black
title.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(title)
NSLayoutConstraint.activate([
title.topAnchor.constraint(equalTo: self.topAnchor, constant: 20),
title.centerXAnchor.constraint(equalTo: self.centerXAnchor)
])
let profile = UIButton()
let profileImage = UIImage(named: "person-icon")
profile.setImage(profileImage, for: .normal)
profile.setImage(UIImage(named: "think-icon"), for: .highlighted)
profile.addTarget(self, action: #selector(profileTapped), for: .touchUpInside)
profile.backgroundColor = .systemBlue
profile.frame.size = CGSize(width: 30, height: 30)
profile.isUserInteractionEnabled = true
profile.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(profile)
NSLayoutConstraint.activate([
profile.centerYAnchor.constraint(equalTo: title.centerYAnchor),
profile.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20),
])
}
#objc func profileTapped(sender: UIButton) {
print("Tapped")
}
}
You forgot set height for BaseHeader
NSLayoutConstraint.activate([
header.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
header.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
header.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: -10),
header.heightAnchor.constraint(equalToConstant: 40) //add more
])
It might be that you are calling the wrong initializer for your custom view and that your setupView() function is not being called. It looks like in the view controller you are calling
let header = BaseHeader()
To initialize the view, but it's this init:
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
That calls your setupView() function and sets up the tap.

UILabel in a custom UIButton that adjusted to the button's size with AutoLayout

I want to have UILabel inside a custom UIButton with constraints to the button size, but to adjust the leading and trailing constraints constants.
The idea is to make the UILabel a bit smaller than the button width (the label takes the font from the button and uses auto shrink).
Adding the relevant code in init with coder of my custom button results with unsatisfied constraints error.
label = UILabel(frame: bounds)
addSubview(label)
translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10.0).isActive = true
label.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
When I remove the "10.0" constant it works ok, but that idea is to give the label a different size, not the exact size of the button.
Any idea?
Thanks
Instead of additional label and constraints, try to set button.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0), and use the regular title of the button.
Instead of regular UIButton, create a subclass of it, and override the intrinsicContentSize method of the button to keep the possibility of autosizing:
class MyButton : UIButton {
open override var intrinsicContentSize: CGSize {
get {
var ics = super.intrinsicContentSize
ics.width = (ics.width < CGFloat(UINT16_MAX)) ? CGFloat(ceil(ics.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right)) : ics.width
ics.height = (ics.height < CGFloat(UINT16_MAX)) ? CGFloat(ceil(ics.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom)) : ics.height
return ics
}
}
}
If you need two labels (native button's titleLabel + your label), the approach is the same:
class MyButton : UIButton {
var labelLeading : NSLayoutConstraint!
var labelTrailing : NSLayoutConstraint!
var labelTop : NSLayoutConstraint!
var labelBottom : NSLayoutConstraint!
let label = UILabel(frame: bounds)
public override init(frame: CGRect) {
super.init(frame: frame)
internalInit()
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
internalInit()
}
private func internalInit() {
addSubview(label)
/// !!! Important to make label to not translate its autoresizing mask, not the button
label.translatesAutoresizingMaskIntoConstraints = false
labelLeading = label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10.0)
labelTrailing = label.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
labelTop = label.topAnchor.constraint(equalTo: topAnchor)
labelBottom = label.bottomAnchor.constraint(equalTo: bottomAnchor)
NSLayoutConstraint.activate([labelLeading, labelTrailing, labelTop, labelBottom)
}
open override var intrinsicContentSize: CGSize {
get {
var ics = super.intrinsicContentSize
ics.width = (ics.width < CGFloat(UINT16_MAX)) ? CGFloat(ceil(ics.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right)) : ics.width
ics.height = (ics.height < CGFloat(UINT16_MAX)) ? CGFloat(ceil(ics.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom)) : ics.height
return ics
}
}
}
Found the solution, had to add the translatesAutoresizingMaskIntoConstraints also to the label:
label.translatesAutoresizingMaskIntoConstraints = false

Wrap label around UIbutton

I'm trying to create a view like below using storyboard in Xcode.
For this, I've added a button and a label with constraints but this is the result I get. The text doesn't start below the checkbox. One way to achieve this would be to create 2 labels and add the strings that start after this string to 2 label and place it under the first label.
Is there any better way to do this? Also, when you click on Read more the text can expand as well.
You can make the leading of the button and the label the same ( button above label ) and insert some empty characters at the beginning of the label text
You can do a way. Take the button and the label in a view
then sub divide the view into two views, left one holds the button and right one holds the label. make a gap between left and right
button's constraint will be leading , top and trailing to zero and height as your wish
label's constraint will be leading , top, trailing and bottom.
You can accomplish this by using a UITextView and setting an ExclusionPath.
The ExclusionPath (or paths) defines an area within the text view's textContainer around which the text should wrap.
If you disable scrolling, selection and editing of the UITextView it will behave just like a UILabel but will also give you the benefit of ExclusionPath
Here is a simple example - lots of hard-coded values, so you'd probably want to make it a custom class - but this should get you on your way:
class TextViewLabel: UITextView {
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() -> Void {
isScrollEnabled = false
isEditable = false
isSelectable = false
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
}
}
class ExclusionViewController: UIViewController {
let checkBox: UIButton = {
let v = UIButton()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let theTextViewLabel: TextViewLabel = {
let v = TextViewLabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .yellow
v.text = "I agree to receive information about this application and all the updates related to this..."
v.font = UIFont.systemFont(ofSize: 20.0)
return v
}()
var isChecked: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(theTextViewLabel)
theTextViewLabel.addSubview(checkBox)
let cbWidth = CGFloat(20)
NSLayoutConstraint.activate([
theTextViewLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 100.0),
theTextViewLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 40.0),
theTextViewLabel.widthAnchor.constraint(equalToConstant: 240.0),
checkBox.topAnchor.constraint(equalTo: theTextViewLabel.topAnchor, constant: 2.0),
checkBox.leadingAnchor.constraint(equalTo: theTextViewLabel.leadingAnchor, constant: 0.0),
checkBox.widthAnchor.constraint(equalToConstant: cbWidth),
checkBox.heightAnchor.constraint(equalToConstant: cbWidth),
])
theTextViewLabel.textContainer.exclusionPaths = [
UIBezierPath(rect: CGRect(x: 0, y: 0, width: cbWidth + 8.0, height: cbWidth))
]
updateCheckboxImage()
checkBox.addTarget(self, action: #selector(checkBoxTapped), for: .touchUpInside)
}
func updateCheckboxImage() -> Void {
if isChecked {
checkBox.setImage(UIImage(named: "SmallChecked"), for: .normal)
} else {
checkBox.setImage(UIImage(named: "SmallUnChecked"), for: .normal)
}
}
#objc func checkBoxTapped() -> Void {
isChecked = !isChecked
updateCheckboxImage()
}
}
Result:
(I used these two images for the checkBox):

Add UILabel as subview of UITextField on top

I am in the process of implementing a UILabel as a subview of a UITextField which will be shown right above the UITextField itself. The UITextField has a rounded border and what I would like to achieve is the UILabel to be shown over the border.
Everything currently works as expected, but the UILabel is drawn behind the border of the UITextField. I want it to go "over" (above) the border so the white backgroundColor would be shown above part of the border and make the text more easily readible.
var priceTextField: CustomTextField = {
let priceTextField = CustomTextField()
priceTextField.layer.cornerRadius = 10.0
priceTextField.layer.borderWidth = 1.0
priceTextField.layer.borderColor = UIColor.darkGray.cgColor
priceTextField.translatesAutoresizingMaskIntoConstraints = false
priceTextField.font = UIFont.systemFont(ofSize: 15)
priceTextField.textColor = .black
priceTextField.text = "0"
priceTextField.suffix = "EUR"
priceTextField.suffixTextColor = .darkGray
priceTextField.suffixSpacing = 2.0
priceTextField.textAlignment = .center
priceTextField.labelText = "Price"
return priceTextField
}()
In my CustomTextField class (subclass of UITextField):
public var labelText: String?
var topLabel: UILabel = {
let topLabel = UILabel()
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.textAlignment = .center
topLabel.font = UIFont.systemFont(ofSize: 12)
topLabel.textColor = .lightGray
topLabel.backgroundColor = .white
topLabel.numberOfLines = 1
return topLabel
}()
func setupLabel() {
self.addSubview(topLabel)
topLabel.centerYAnchor.constraint(equalTo: self.topAnchor).isActive = true
topLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true
topLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
topLabel.text = labelText
}
I call setupLabel() at the end of the draw(_ rect: CGRect) method of UITextField (because I work with this to show the EUR sign always behind the entered value).
I have tried to play around with bringSubviewToFront and changing the zPosition of the layer of the UILabel, without success.
It now looks like this:
How can I bring the text "above" the border on the top?
EDIT: Tried Sh_Khan's solution, but it's still hidden behind the border.
import Foundation
import UIKit
public class CustomTextView: UIView, UITextFieldDelegate {
public var labelText: String?
var customTextField: CustomTextField = {
let customTextField = CustomTextField()
customTextField.translatesAutoresizingMaskIntoConstraints = false
customTextField.font = UIFont.systemFont(ofSize: 15)
customTextField.textColor = .black
customTextField.textAlignment = .center
customTextField.text = "0"
customTextField.suffix = "EUR"
customTextField.suffixTextColor = .lightGray
customTextField.suffixSpacing = 2.0
return customTextField
}()
var topLabel: UILabel = {
let topLabel = UILabel()
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.font = UIFont.systemFont(ofSize: 12)
topLabel.textColor = .darkGray
topLabel.numberOfLines = 1
topLabel.backgroundColor = .red
topLabel.textAlignment = .center
return topLabel
}()
override public init(frame: CGRect) {
super.init(frame: frame)
setupBorders()
}
public override func layoutSubviews() {
setupViews()
}
func setupBorders() {
self.layer.cornerRadius = 10.0
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.borderWidth = 1.0
}
func setupViews() {
addSubview(topLabel)
// insertSubview(topLabel, aboveSubview: customTextField)
insertSubview(customTextField, belowSubview: topLabel)
customTextField.topAnchor.constraint(equalTo: topAnchor).isActive = true
customTextField.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
customTextField.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
customTextField.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
topLabel.centerYAnchor.constraint(equalTo: topAnchor).isActive = true
topLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
topLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
topLabel.text = labelText
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
}
You can try to organize it by creating a UIView subclass , so everything appear properly in it's order of adding
class CustomView: UIView {
var priceTextField: CustomTextField = {
let priceTextField = CustomTextField()
priceTextField.layer.cornerRadius = 10.0
priceTextField.layer.borderWidth = 1.0
priceTextField.layer.borderColor = UIColor.darkGray.cgColor
priceTextField.translatesAutoresizingMaskIntoConstraints = false
priceTextField.font = UIFont.systemFont(ofSize: 15)
priceTextField.textColor = .black
priceTextField.text = "0"
priceTextField.suffix = "EUR"
priceTextField.suffixTextColor = .darkGray
priceTextField.suffixSpacing = 2.0
priceTextField.textAlignment = .center
priceTextField.labelText = "Price"
return priceTextField
}()
var topLabel: UILabel = {
let topLabel = UILabel()
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.textAlignment = .center
topLabel.font = UIFont.systemFont(ofSize: 12)
topLabel.textColor = .lightGray
topLabel.backgroundColor = .white
topLabel.numberOfLines = 1
return topLabel
}()
var lableStr:String?
init(frame: CGRect,lblTex:String) {
super.init(frame: frame)
lableStr = lblTex
createSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
createSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
createSubviews()
}
func createSubviews() {
// all the layout code from above
// add the textfield then the label and set constraints properly
}
}
According to the Apple specification: It is composited above the receiver’s contents and sublayers.
So, the border will always be above all subviews, even if one brings the subview to the front and so on.
So one needs to make a background view to fake the border.
similar to Stackoverflow Question
Example:
Here self is "TextField"
activeborderView is "UiView"
activeborderView.frame = CGRect.init(x: -1, y: -1, width: self.frame.size.width+2, height: self.frame.size.height+2)
activeborderView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(activeborderView)
activeborderView.topAnchor.constraint(equalTo: self.topAnchor, constant:-1).isActive = true // Place our label 10 pts above the text field
activeborderView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: -1).isActive=true
activeborderView.heightAnchor.constraint(equalToConstant: self.frame.size.height+2).isActive=true
activeborderView.widthAnchor.constraint(equalToConstant: self.frame.size.width+2).isActive=true
activeborderView.layer.borderWidth = 3
activeborderView.layer.borderColor = CustomColor.blue().cgColor
activeborderView.layer.cornerRadius = 5
activeborderView.backgroundColor = .white
self.sendSubviewToBack(activeborderView)
self.setNeedsDisplay()

Resources