Can't get UITextField to autoshrink the font - ios

In Swift, i have a UITextField on a table view cell, and when it's text becomes too long I would like the font size to decrease. I want to make it very clear that I am talking about a UITextField, not a UILabel or a UITextView. The reason I say this is because I have seen this question pop up several times and the answers were all based on UILabel instead of UITextField.
I hoped, that can be done in IB, where i did this settinngs of Min Font Size and ajust to fit, but this didnĀ“t change anything:
Is there another way to resolve this?

extension UITextField {
internal func resizeText() {
if let text = self.text{
self.font = UIFont.systemFontOfSize(14)
let textString = text as NSString
var widthOfText = textString.sizeWithAttributes([NSFontAttributeName : self.font!]).width
var widthOfFrame = self.frame.size.width
// decrease font size until it fits
while widthOfFrame - 5 < widthOfText {
let fontSize = self.font!.pointSize
self.font = self.font?.fontWithSize(fontSize - 0.5)
widthOfText = textString.sizeWithAttributes([NSFontAttributeName : self.font!]).width
widthOfFrame = self.frame.size.width
}
}
}
}
Based on the answer I linked, I created an extension to UITextField that automatically resizes text - to have it properly resize the text each time, it needs to be called in a number of locations:
override func drawRect(rect: CGRect) (I haven't found a better spot to call this as you have to wait until its bounds are set and the TVC lifecycle gets confusing)
textField(textField: UITextField, shouldChangeCharactersInRange...

Related

How to show the full placeholder text in an ios UITextfield?

The placeholder text does show the triple points to cut off the text.
The text doesn't even take half of the textfield width, and the three points are longer than the text. Is there a way to go inside the field and adjust the threshold to avoid the cutoff?
I do know the programatic way, and use that for the moment, to resize the placeholder tekst, till it fits.
let labelKeyPath: String = "_placeholderLabel"
var label : UILabel = self.Distance.value(forKeyPath: labelKeyPath) as! UILabel
label.adjustsFontSizeToFitWidth = true
label = self.FocalLength.value(forKeyPath: labelKeyPath) as! UILabel
label.adjustsFontSizeToFitWidth = true
Herby I do add some images of the current IB settings and results. Please keep adding points to let me show the current and future images embedded, thank you.
The IB view, settings and app result
Alternative you can create your own UITF subclass and override:
open func placeholderRect(forBounds bounds: CGRect) -> CGRect
You can customize the textfield to fix you issue. put this CustomTextField in your Storyboard textfield class type. here am setting minimum scaling factor to 0.3. that helps to fix the ...
class CustomTextField: UITextField {
override func layoutSubviews() {
super.layoutSubviews()
for subview in subviews {
if let label = subview as? UILabel {
label.minimumScaleFactor = 0.3
label.adjustsFontSizeToFitWidth = true
}
}
}
}
You should change Autolayouts Constraints with leading, center vertically with Distance and horizontal space with the Distance.
You can also wrap up text with resize the textfield using minimum font size.

iOS TextField view glides out of layout

I'm using TextField in my app. I made it to wrap the content.
The problem is when the user types a long text the TextField edges glides out of the layout and make some of the view invisible.
is there a way to disable it to expend when it reaches to the layout edges?
The best thing to do is to change your UITextField to a UITextView. Here's a function that I like to use quite a lot for this autoresize technique that you'll see in the likes of Apples iMessage:
func containerViewHeight() {
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
containerView.heightAnchor.constraint(equalToConstant: size.height + 24)
self.textView.setContentOffset(.zero, animated: false)
}
You'll want to call this function initially inside of your viewDidLoad:
override func viewDidLoad() {
self.containerViewHeight()
}
As well as that, you'll want to conform to the UITextViewDelegate methods by subclassing it at the top of your file like so:
class YourViewController: UIViewController, UITextViewDelegate
Once you add this AND you have used self.textView.delegate = self inside of your viewDidLoad:
override func viewDidLoad() {
self.textView.delegate = self
}
you'll then be able to use the textViewDidChange method for that textView, so the final thing you'll want to add in your class is this:
func textViewDidChange(_ textView: UITextView) {
self.containerViewHeight()
}
Your textField probably doesn't have a fixed width.
Just put a width constraint to your textField in your storyboard so it will always have the same width, no matter if the text is too long.
Edit : if you want a maximum width, you can add 2 width constraints to your textField. One for minimum width and one for maximum width. This way the width of your textField will vary between 100 and 200, depending on the text it contains.
Minimum width constraint :
Maximum width constraint :

iOS 9 - UITextView shrink font size to fill text view without scrolling?

I have a UITextView that contains text that may range from a few words to a lot of words.
While using the app, the text view has a fixed height and scrolling is enabled so the user can view any potentially long text.
However, the user is allowed to "share" the screen using the native share features. During this process, I take a screenshot of the screen to use for the image, along with a few other added UI elements. Since you can't scroll a screenshot, I disabled the UITextView's scrolling ability and attempt to shrink the font of any long text, while increasing the font of any small text so that the UITextView is filled as best as possible.
This use to work on older versions of iOS, but iOS 9 seems to have some issues and now it cuts off some of the text:
One side note, this view is built in a XIB file and uses autolayout.
override func awakeFromNib() {
super.awakeFromNib()
self.translatesAutoresizingMaskIntoConstraints = false
if UIDevice.iPad() || UIDevice.iPadPro() {
bobbleheadViewWidthConstraint.constant = 300.0
bobbleheadViewHeightConstraint.constant = 600.0
self.updateConstraintsIfNeeded()
self.layoutIfNeeded()
}
speechBubbleView.roundCornersWithRadius(5.0)
}
class func shareViewForQuote(quote: Quote) -> BTVShareView? {
if let shareView = UINib(nibName: "BTVShareView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as? BTVShareView {
shareView.bobbleheadView.image = UIImage(named: quote.character!.name!.stringByReplacingOccurrencesOfString(" ", withString: "-"))
shareView.textView.text = quote.text
shareView.textView.font = UIFont.systemFontOfSize(60.0)
// Re-size quote text
shareView.updateTextFont()
return shareView
}
return nil
}
func updateTextFont() {
let minFontSize: CGFloat = 1.0
var currentFontSize: CGFloat = 100.0
while (currentFontSize > minFontSize && textView.sizeThatFits(CGSizeMake(textView.frame.size.width, textView.frame.size.height)).height >= textView.frame.size.height) {
currentFontSize -= 1.0
textView.font = textView.font!.fontWithSize(currentFontSize)
}
}
So a better solution was to just use a UILabel for the share screen, since I don't need a UITextView anyways.
Still curious what the proper way to adjust font size to fit text to UITextView would be though...

how to stop text overlapping in textfield

I have created an image for textfield in my iOS app. But the text seems to overlap the image. Is there any way to prevent this or achieve the same design in another way. Below is the image of the problem I'm facing.
Is there any way to make the text start from a particular position in the text field?
One solution is to make your UITextField a subclass of UITextField. This will allow you to override textRectForBounds: - and now you are in charge of where the text will go.
In particular, in your override, call super to get the original rect. Now increase the x-component of the origin by some amount to allow room for your image, and decrease the width of the size by that same amount. Return the resulting modified rect and you're done.
This will allow you to change the rect where the text will go:
class MyCustomTextField : UITextField {
var leftMargin : CGFloat = 10.0
override func textRectForBounds(bounds: CGRect) -> CGRect {
var newBounds = bounds
newBounds.origin.x += leftMargin
return newBounds
}
override func editingRectForBounds(bounds: CGRect) -> CGRect {
var newBounds = bounds
newBounds.origin.x += leftMargin
return newBounds
}
}
I did also find another way to achieve this by adding offset to the textfield. But found out this would not be an ideal solution when you have multiple text fields in the same view. Just adding the solution as a reference to others so that someone finds it helpful.
let paddingView = UIView(frame: CGRectMake(0, 0, 60, self.yourTextField.frame.height))
yourTextField.leftView = paddingView
yourTextField.leftViewMode = UITextFieldViewMode.Always

Resizing accessoryInputView?

I have tried and failed to resize a UITextField that resides inside an UIView, that is set as the inputAccessoryView of that text field.
Now I have been trying to get the resizing to work. When the user enters text of 2 lines or more, the textfield should resize, and so should the surrounding view (inputAccessoryView).
I have the following code in my UITextFieldDelegate:
func textViewDidChange(textView: UITextView) {
println("textViewDidChange called")
sendButton.enabled = textView.hasText()
var oldHeight = textView.frame.height
var textWidth = textView.frame.width
textView.sizeToFit()
var textFrame = textView.frame
textFrame.size.height = textView.contentSize.height
textFrame.size.width = textWidth
textView.frame = textFrame
var newHeight = textView.frame.height
moveToolbarUp(newHeight - oldHeight)
self.frame.size.height += newHeight - oldHeight
self.superview?.updateConstraints()
}
Now when I type too much in the textfield, this happens. How can I make sure this does not happen? Also, the complete inputAccessoryView resets when I press the return key. Should I be using another method in the delegate? Should I not be calculating these heights myself? Why doesn't my inputAccessoryView resize properly, but only my textView?
As I was using Autolayout, I should have used that... It works by setting a height constraint on the UITextField, which I then change with these calculations...

Resources