UITextField cursor size [duplicate] - ios

i'm working on a project(Swift4,Xcode 9.2) which has a feature to get text input and the blinking bar/line should be of big size (it should be Square instead of bar/line), so i placed a UITextField for Text but i don't understand how to change the size of that blinking line/bar.
So, is it possible to change the size of line/bar? and if Yes then how to do it?
i know how to change the color of that line/bar but this is something different.

You can change the size by overriding the frame method for cursor as follows,
class CustomTextField: UITextField {
override func caretRect(for position: UITextPosition) -> CGRect {
var rect = super.caretRect(for: position)
let size = CGSize(width: 10, height: 50)
// Calculating center y
let y = rect.origin.y - (size.height - rect.size.height)/2
rect = CGRect(origin: CGPoint(x: rect.origin.x, y: y), size: size)
return rect
}
}
Set CustomTextField class in xib/storyboard identity inspector for that textField.

We can't change the cursor height, but we can do some trick, select your textfield and change your textfield border style as UITextBorderStyleNone
Check the below link which is already given answer
there after increase the font size of your textfield whatever you want, then you get the output as

There are some unnecessary lines of codes, so this is the revised:
class CustomTextField: UITextField {
override func caretRect(for position: UITextPosition) -> CGRect {
var rect = super.caretRect(for: position)
rect = CGRect(x: rect.origin.x, y: .zero, width: 15, height: 30)
return rect
}
}

Related

UITextField shrinks text before necessary

I have a UITextField for which I've set autoAdjustFontSizeToFitWidth to true and minimumFontSize to 0. The problem is the setting shrinks the text noticeably sooner than it really should. For example, here is an image of a UITextField with the above settings:
The green is the background color of the UITextField. In this example, the text has not shrunk yet, but no matter what I type as the next character the text field always begins shrinking; despite clearly being enough room on the left side for a few more characters. Here is another image with additional characters entered:
As you can see, there is a relatively large area on the left side that the text field won't place text in when auto adjusting. This is for a right aligned text field. The same can be said of center aligned text fields as well, where there is space on the left and right that seems as if an auto adjusting text field won't place text inside.
How do I get it so that auto adjusting text fields use the entire available space?
Update:
You can do the text calculations and font resizing manually. By doing so you will avoid hacks and future compatibility issues.
A simple implementation looks like this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var originalFont: UIFont!
override func viewDidLoad() {
super.viewDidLoad()
self.textField.font = self.textField.font?.withSize(44)
self.textField.adjustsFontSizeToFitWidth = false
self.originalFont = textField.font
self.textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
}
#objc
func textFieldDidChange(sender: UITextField) {
let textRect = sender.textRect(forBounds: sender.bounds)
let textWidth = textRect.width
var currentFont = self.originalFont!
var i = 0
while (i < 10) {
let unrestrictedTextWidth = sender.text!.boundingRect(with: CGSize(width: .greatestFiniteMagnitude,
height: textRect.height),
attributes: [.font : currentFont],
context: nil).width
if unrestrictedTextWidth <= textWidth {
break
}
let factor = textWidth / max(textWidth, unrestrictedTextWidth)
let originalSize = currentFont.pointSize
currentFont = self.originalFont!.withSize(originalSize * factor)
i += 1
}
sender.font = currentFont
}
}
Interestingly the actual relationship between text rect and font size is non-linear and non-trivial. So I added multiple iteration steps to approximate the correct size. I chose a maximum of 10 iterations to avoid infinite loops on very small sizes and rounding errors.
Original Answer:
There has always been some magic around UITextField and adjustsFontSizeToFitWidth. See for example this post from 2015 about how the initial font size affects the minimum font size:
https://stackoverflow.com/a/30881385/921573
A UITextField with:
Font size 17, minimum size 15 will go down to 15 if need be
Font size 17, minimum size 10 will only go down to 14
Font size 13, minimum size 4 will stay at 13
In my tests, setting the minimum font size in IB to 0 just gets ignored – in order so see the shrinking effect it has to be a small value like 1.
Setting it in code to 0 works fine.
So I think it is safe to say that UITextField might be considered historically buggy when it comes to adjustsFontSizeToFitWidth.
That being said, I found a workaround for you:
class FixedTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
let magicNumber = -15.0
if self.adjustsFontSizeToFitWidth {
return CGRect(
x: bounds.origin.x + magicNumber,
y: bounds.origin.y,
width: bounds.size.width - magicNumber,
height: bounds.size.height
)
} else {
return super.textRect(forBounds: bounds)
}
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.textRect(forBounds: bounds)
}
}
This custom text field uses countermagic to mitigate the issue.
You may have to play with the magicNumber according to your font or dimensions or device. For me 15 works ok:
This works for me and the textField.textAlignment is set to .right (it will depend on how many characters you put in the textField though) :
class TextFieldOne: UITextField {
override func alignmentRect(forFrame frame: CGRect) -> CGRect {
// let newWidth = frame.width + 10 // if you want to reduce the right side too.
let x = frame.origin.x - 15 // suit yourself here
let newFrame = CGRect(x: x, y: frame.origin.y, width: frame.width, height: frame.height)
return newFrame
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.alignmentRect(forFrame: self.bounds)
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return self.alignmentRect(forFrame: self.bounds)
}
}

Increasing slider width : swift

I'm using UISlider in swift to show slider on my app. Is there a way by which we can increase the width of the slider ?
I have tried to transform the slider using CGAffineTransform. But this also increases the thumb size.
testslider.transform = CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 2))
I just need to increase width of the slider line but not the thumb size. Is there any way we can do that? Please suggest.
Try the following code
open class CustomSlider : UISlider {
#IBInspectable open var trackWidth:CGFloat = 2 {
didSet {setNeedsDisplay()}
}
override open func trackRect(forBounds bounds: CGRect) -> CGRect {
let defaultBounds = super.trackRect(forBounds: bounds)
return CGRect(
x: defaultBounds.origin.x,
y: defaultBounds.origin.y + defaultBounds.size.height/2 - trackWidth/2,
width: defaultBounds.size.width,
height: trackWidth
)
}
}

How to change the size of blinking bar/line for specific UITextField?

i'm working on a project(Swift4,Xcode 9.2) which has a feature to get text input and the blinking bar/line should be of big size (it should be Square instead of bar/line), so i placed a UITextField for Text but i don't understand how to change the size of that blinking line/bar.
So, is it possible to change the size of line/bar? and if Yes then how to do it?
i know how to change the color of that line/bar but this is something different.
You can change the size by overriding the frame method for cursor as follows,
class CustomTextField: UITextField {
override func caretRect(for position: UITextPosition) -> CGRect {
var rect = super.caretRect(for: position)
let size = CGSize(width: 10, height: 50)
// Calculating center y
let y = rect.origin.y - (size.height - rect.size.height)/2
rect = CGRect(origin: CGPoint(x: rect.origin.x, y: y), size: size)
return rect
}
}
Set CustomTextField class in xib/storyboard identity inspector for that textField.
We can't change the cursor height, but we can do some trick, select your textfield and change your textfield border style as UITextBorderStyleNone
Check the below link which is already given answer
there after increase the font size of your textfield whatever you want, then you get the output as
There are some unnecessary lines of codes, so this is the revised:
class CustomTextField: UITextField {
override func caretRect(for position: UITextPosition) -> CGRect {
var rect = super.caretRect(for: position)
rect = CGRect(x: rect.origin.x, y: .zero, width: 15, height: 30)
return rect
}
}

Change the height of UISegmented Control using IB?

How can i change the height of UISegmented control. I'm using Swift 3.0 with xcode 8. Height property is disabled by default.
I found this:
https://stackoverflow.com/a/41889155/7652057
#IBDesignable class MySegmentedControl: UISegmentedControl {
#IBInspectable var height: CGFloat = 29 {
didSet {
let centerSave = center
frame = CGRect(x: frame.minX, y: frame.minY, width: frame.width, height: height)
center = centerSave
}
}
}
https://stackoverflow.com/a/37716960/7652057
One of three options from the link,
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let rect = CGRect(origin: segment.frame.origin, size: CGSize(width: segment.frame.size.width, height: 100))
segment.frame = rect
}
Ok, I was trying to do it for a long while and here is the solution.
Firstly, It is possible within IB but for that we need to have a good bunch of autolayout constraints.
I've placed that Segmented control in a UIVIew with all the edges pinned inside it.
Then I gave the desired height to that view and it worked.
Also.. thanks to all of your answer
It's very easy. You can access it programmaticly by using frame's height:
yourSegmentedControllOutlet.frame.size.height = yourHeight

How to customise UISlider height

I have project in which have to customise UISlider element.
I wondering if someone knows how to change, or is it possible to change height of UISlide bar line.
I tried something like this but don't work:
let customBounds = CGRect(origin: bounds.origin,
size: CGSize(width: bounds.size.width, height: 15.0))
feedbackSlider.trackRectForBounds(customBounds)
Thanks
i hope that you want edit it in storyboard, and only the line size, use it in your custom UISlider
class CustomSlide: UISlider {
#IBInspectable var trackHeight: CGFloat = 2
override func trackRectForBounds(bounds: CGRect) -> CGRect {
//set your bounds here
return CGRect(origin: bounds.origin, size: CGSizeMake(bounds.width, trackHeight))
}
}
Overriding trackRect is a way to go, however if you're using additional UISlider's views like minimumValueImage, maximumValueImage you would also need to take their bound into account, otherwise they will overlap with slider’s track. As a shortcut you can simply use super's func:
Fixed version.
Swift 3+
#IBDesignable
class CustomSlider: UISlider {
/// custom slider track height
#IBInspectable var trackHeight: CGFloat = 3
override func trackRect(forBounds bounds: CGRect) -> CGRect {
// Use properly calculated rect
var newRect = super.trackRect(forBounds: bounds)
newRect.size.height = trackHeight
return newRect
}
}
You can override a method in you custom slider
For Objective-C
- (CGRect)trackRectForBounds:(CGRect)bounds {
CGRect rect = CGRectMake(0, 0, 100, 30);//change it to any size you want
return rect;
}
For Swift
override func trackRectForBounds(bounds: CGRect) -> CGRect {
var rect:CGRect = CGRectMake(0, 0, 100, 30)
return rect
}
Swift 3
class MySlide: UISlider {
#IBInspectable var height: CGFloat = 2
override func trackRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(origin: bounds.origin, size: CGSize(width: bounds.width, height: height))
}
}
Swift 4 version without thumbImage.
class CustomSlider: UISlider {
#IBInspectable var trackHeight: CGFloat = 2
override func trackRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(origin: bounds.origin, size: CGSize(width: bounds.width, height: trackHeight))
}
}
I think the answers above have a flaw: the origin of the track rect must be offset to account for the change in height of the track, otherwise it will show up off-center. Here is the way I did it:
class CustomSlider: UISlider {
#IBInspectable var sliderTrackHeight : CGFloat = 2
override func trackRect(forBounds bounds: CGRect) -> CGRect {
let originalRect = super.trackRect(forBounds: bounds)
return CGRect(origin: CGPoint(x: originalRect.origin.x, y: originalRect.origin.y + (sliderTrackHeight / 2)), size: CGSize(width: bounds.width, height: sliderTrackHeight))
}
}
U can easily get it done by subclassing UISlider. see following code
class CustomUISlider : UISlider
{
override func trackRectForBounds(bounds: CGRect) -> CGRect {
//set your bounds here
return bounds
}
}
You should be able to subclass the UISlider and then implement:
- (CGRect)trackRectForBounds:(CGRect)bounds
Just return the new CGRect here.
If you're using autolayout you can set a height constraint on the UISlider in the storyboard. if you need to change it at runtime - create an IBOutlet for the constraint and modify its .constant value.

Resources