How to vertically and horizontally align text in SkyFloatingLabelTextField? - ios

I have use SkyFloatingLabelTextField and I want to vertically and horizontally center align text.
I have to write code but it aligns text only horizontally not vertically.
what I have tried is
var rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 25, height: 25))
var imageNew = UIImage(named: "rightArrow")!
rightButton.contentMode = .scaleAspectFit
rightButton.setImage(imageNew, for: .normal)
rightButton.setImage(imageNew, for: .selected)
rightButton.contentVerticalAlignment = .center
rightButton.contentHorizontalAlignment = .center
selectTradeTxt.rightView = rightButton
selectTradeTxt.rightView?.frame = self.selectTradeTxt.rightViewRect(forBounds: self.selectTradeTxt.bounds)
selectTradeTxt.rightViewMode = .always
selectTradeTxt.textColor = .white
selectTradeTxt.addRoundCorner(7)
// i have tried this
// selectTradeTxt.contentHorizontalAlignment = .center
selectTradeTxt.contentVerticalAlignment = .center
selectTradeTxt.textAlignment = .center

You have to change frame y position as bellow override function in SkyFloatingLabelTextField.swift file
// MARK: - UITextField text/placeholder positioning overrides
/**
Calculate the rectangle for the textfield when it is not being edited
- parameter bounds: The current bounds of the field
- returns: The rectangle that the textfield should render in
*/
override open func textRect(forBounds bounds: CGRect) -> CGRect {
let superRect = super.textRect(forBounds: bounds)
let titleHeight = self.titleHeight()
let rect = CGRect(
x: superRect.origin.x,
y: titleHeight + 2,
width: superRect.size.width,
height: superRect.size.height - titleHeight - selectedLineHeight
)
return rect
}
/**
Calculate the rectangle for the textfield when it is being edited
- parameter bounds: The current bounds of the field
- returns: The rectangle that the textfield should render in
*/
override open func editingRect(forBounds bounds: CGRect) -> CGRect {
let superRect = super.editingRect(forBounds: bounds)
let titleHeight = self.titleHeight()
let rect = CGRect(
x: superRect.origin.x,
y: titleHeight + 2,
width: superRect.size.width,
height: superRect.size.height - titleHeight - selectedLineHeight
)
return rect
}
/**
Calculate the rectangle for the placeholder
- parameter bounds: The current bounds of the placeholder
- returns: The rectangle that the placeholder should render in
*/
override open func placeholderRect(forBounds bounds: CGRect) -> CGRect {
let rect = CGRect(
x: 0,
y: self.isEditing ? titleHeight() : titleHeight() - 8,
width: bounds.size.width,
height: bounds.size.height - titleHeight() - selectedLineHeight
)
return rect
}
// MARK: - Positioning Overrides
/**
Calculate the bounds for the title label. Override to create a custom size title field.
- parameter bounds: The current bounds of the title
- parameter editing: True if the control is selected or highlighted
- returns: The rectangle that the title label should render in
*/
open func titleLabelRectForBounds(_ bounds: CGRect, editing: Bool) -> CGRect {
if editing {
return CGRect(x: 0, y: 10, width: bounds.size.width, height: titleHeight())
}
return CGRect(x: 0, y: titleHeight(), width: bounds.size.width, height: titleHeight())
}

Related

Placeholder text not centered in iOS

I have created text field with Rounded Corners. All is good with the position of the cursor and also when i type the text. But the Placeholder text is off. Is there a way for the placeholder position to follow the Text field.
Below code overrides from the UITextField functions to reposition the cursor.
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: 0 + textOffset,
y: 0 + (textOffset / 2),
width: self.frame.width - textOffset,
height: self.frame.height + textOffset)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: 0 + textOffset,
y: 0 + (textOffset / 2),
width: self.frame.width - textOffset,
height: self.frame.height + textOffset)
Use this override method to set placeholderRect
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return UIEdgeInsetsInsetRect(bounds, paddingInsets)
}
You can use attributedPlaceholder paragraph styles you can center the placeholder in a UITextField.
let textField = UITextField(frame: CGRect(x: 0, y: 100, width: self.view.frame.size.width, height: 60))
textField.backgroundColor = UIColor.gray
let centeredParagraphStyle = NSMutableParagraphStyle()
centeredParagraphStyle.alignment = .center
let attributedPlaceholder = NSAttributedString(string: "Placeholder", attributes: [NSAttributedStringKey.paragraphStyle: centeredParagraphStyle])
textField.attributedPlaceholder = attributedPlaceholder
What worked for me was creating baselineOffset attribute and then setting the attributedPlaceholder.
let attributes = [NSAttributedString.Key.baselineOffset : NSNumber(2.0)]
myTextField.attributedPlaceholder = NSAttributedString(string: "Placeholder", attributes: attributes)

UITextField padding

Im having trouble creating padding for leftView property of UITextField. The code I have now creates padding for the text which is nice, but I need it for the imageView.
UITextField Subclass method:
Notice x position of paddingView frame doesn't extend view to the right like expected.
func setLeftView(imageView: UIImageView, withPadding padding: CGFloat) {
let height = imageView.frame.height
let width = imageView.frame.width + padding
let paddingView = UIView(frame: CGRect(x: 36, y: 0, width: width, height: height))
paddingView.addSubview(imageView)
self.leftView = paddingView
self.leftViewMode = .always
}
Result:
You need to make changes in your function, just set frame of imageView and set paddingView's X position to 0
func setLeftView(imageView: UIImageView, withPadding padding: CGFloat) {
let height = imageView.frame.height
let width = imageView.frame.width + padding
// Set x position to 0
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: height))
/// You need to set frame of imageView so put this line
imageView.frame = CGRect(x: padding, y: 0, width: imageView.frame.width, height: height)
paddingView.addSubview(imageView)
self.leftView = paddingView
self.leftViewMode = .always
}
you have to override:
override func leftViewRect(forBounds bounds: CGRect) -> CGRect

Wrong position of CAShapelayer in sublayers of UIView

I'm trying to draw: O-O-O in the midY of UIView but get:
Here is a func for calculating position for CAShapeLayer.frame. Even indices are dots and odd indices are lines. Number of lines is always minus one number of dots.
func frameForShape(at index: Int) -> CGRect {
let dotWidth = dotRadius * 2
let lineWidth = (view.bounds.width - (CGFloat(numberOfDots) * dotWidth)) / CGFloat(numberOfLines)
if index % 2 == 0 {
let count = CGFloat(index) / 2
let x = (lineWidth * count) + (dotWidth * count)
return CGRect(x: x, y: 0, width: dotWidth, height: view.bounds.height)
} else {
let count = Double(index) / 2
let x = (lineWidth * CGFloat(floor(count))) + (dotWidth * CGFloat(ceil(count)))
return CGRect(x: x, y: 0, width: lineWidth, height: view.bounds.height)
}
}
func setFrame() {
for (index, shape) in shapes.enumerated() {
shape.frame = frameForShape(at: index)
}
}
frameForShape(at:) correctly return frame position and size
This funcs draw a path in the center of given frame
func linePath(rect: CGRect) -> UIBezierPath {
let newRect = CGRect(x: rect.minX, y: rect.midY - (lineHeight / 2), width: rect.width, height: lineHeight)
let path = UIBezierPath(rect: newRect)
return path
}
func dotPath(rect: CGRect) -> UIBezierPath {
let newRect = CGRect(x: rect.midX - dotRadius, y: rect.midY - dotRadius, width: dotRadius * 2, height: dotRadius * 2)
let path = UIBezierPath(ovalIn: newRect)
return path
}
Here, I'm adding CAShapeLayers to yellow UIView
override func awakeFromNib() {
super.awakeFromNib()
for shape in shapes {
view.layer.addSublayer(shape)
}
}
override func layoutSubviews() {
super.layoutSubviews()
layoutIfNeeded()
setFrame()
build()
}
func build() {
for (index, shape) in shapes.enumerated() {
if index % 2 == 0 {
shape.path = dotPath(rect: shape.frame).cgPath
} else {
shape.path = linePath(rect: shape.frame).cgPath
}
}
}
Frames are correct so why dots and lines are misplaced?
I found this answer: https://stackoverflow.com/a/40194019/
incorrect position of your layer - frame should be equal to bounds of parent layer in parentView
But how draw path at specific position if UIBezierPath(ovalIn:) and UIBezierPath(rect:) draw all inside frame?
As the answer says, simply change shape.frame to shape.bounds in your call to build().
Remember that the coordinates of your shape layer are relative to the containing view, so bounds needs to be used.

Custom progress view

I want to do a custom progress view for my iOS app, with 2 dots. Here is my code:
import UIKit
#IBDesignable
class StepProgressView: UIView {
#IBInspectable var progress: Float = 0
var progressColor = UIColor.blackColor()
var bgColor = UIColor.whiteColor()
override func layoutSubviews() {
self.backgroundColor = UIColor.clearColor()
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
let height = frame.height-8
let circle1 = UIView(frame: CGRect(x: frame.width*(1/3), y: 0, width: frame.height, height: frame.height))
circle1.backgroundColor = bgColor
circle1.layer.cornerRadius = frame.height/2
addSubview(circle1)
let circle2 = UIView(frame: CGRect(x: frame.width*(2/3), y: 0, width: frame.height, height: frame.height))
circle2.backgroundColor = bgColor
circle2.layer.cornerRadius = frame.height/2
addSubview(circle2)
let bgView = UIView(frame: CGRect(x: height/2, y: 4, width: frame.width-height/2, height: height))
bgView.backgroundColor = bgColor
bgView.layer.cornerRadius = height/2
addSubview(bgView)
let progressView = UIView(frame: CGRect(x: 0, y: 4, width: frame.width*CGFloat(progress), height: height))
progressView.backgroundColor = progressColor
progressView.layer.cornerRadius = height/2
addSubview(progressView)
}
}
The result:
However, as you can see, the circles aren't "filled" when the progression pass over one of them, and I don't know how to do that. I could create another view but I don't know how to handle the corner radius.
Can you help me ?
Thanks

set the padding of a text field using swift in xcode

How to create some space at the beginning of a text field using swift?
I looked at the post
padding of text field
I don't understand what the subclass is doing and how do I use that class to padding.
Thank you very much
https://stackoverflow.com/a/27066764/846780
This answer is very clear,
If you subclass UITextField you can override textRectForBounds, editingRectForBounds and placeholderRectForBounds. These methods just allow you to add a rect (frame) to your textfield's label.
newBounds method create the rect (frame) that will be added to textfield's label.
Finally your padding is: let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);
Now you have a custom UITextField that has a custom padding.
If you create your new subClass like this class MyTextField: UITextField for example, you only need to change the class of the UITextField that you've added into IB file.
Complementing the answer of klevison-matias this is the code I use when I want to add a padding to my TextField in Swift 3
//UITextField : override textRect, editingRect
class LeftPaddedTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
}
Then in my TextField I use in this way:
let emailTextField: LeftPaddedTextField = {
let textField = LeftPaddedTextField()
textField.placeholder = "Enter email"
textField.layer.borderColor = UIColor.lightGray.cgColor
textField.layer.borderWidth = 1
textField.keyboardType = .emailAddress
return textField
}()
let passwordTextField: LeftPaddedTextField = {
let textField = LeftPaddedTextField()
textField.placeholder = "Enter password"
textField.layer.borderColor = UIColor.lightGray.cgColor
textField.layer.borderWidth = 1
textField.isSecureTextEntry = true
return textField
}()
Create TextField outlet and use following code. Say "nameTextField" has to add padding.
let paddingView = UIView(frame: CGRectMake(x: 0, y: 0, width: 30, height: 30))
nameTextField.leftView = paddingView
nameTextField.leftViewMode = .always
nameTextField.placeholder = "Enter Name"
You can add Image in paddingView.
Based on #Jorge Casariego's answer I came up with this solution.
You can set PaddedTextField class and the desired padding through the Interface Builder!
class PaddedTextField: UITextField {
#IBInspectable var padding: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + padding, y: bounds.origin.y, width: bounds.width - padding * 2, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + padding, y: bounds.origin.y, width: bounds.width - padding * 2, height: bounds.height)
}
}
full code sample:
make sure your TextField points to RoundedTextField via Story board
import UIKit
class RoundedTextField: UITextField {
override func awakeFromNib() {
// add rounded corner
self.layer.cornerRadius = 15.0
self.clipsToBounds = false
super.awakeFromNib()
}
// For the padding from the left
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 15.0, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 15.0, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
}

Resources