Resizing accessoryInputView? - ios

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...

Related

Dynamic UITextView Size (Swift 4)

I want size a UITextView dynamically to its contents by restricting both its width and its height to some maximums.
In particular, the textView should have a minimum width and height if there is little data (e.g., "Lorem"). As the data grows (e.g., "Lorem ipsum") it should expand in width as until it hits the maximum width ("Lorem ipsum dolor sit"), and then expand in height until it hits that maximum height. Once it goes beyond the max width and height it should become scrollable.
So far, I am struggling to get just the height working. I have experimented with a number of methods and, while this seemed the simplest and most promising, it just crashes.
func textViewDidChange(_ textView: UITextView ) {
resizeTextView(txtview1)
}
#IBOutlet weak var txtViewHeight: NSLayoutConstraint!
func resizeTextView(_ textView: UITextView ) {
let minHeight: CGFloat = 20.0
let maxHeight: CGFloat = 40.0
txtViewHeight.constant = min(maxHeight, max(minHeight, textView.contentSize.height))
self.view.layoutIfNeeded()
}
So, I changed the resize function to this - which kinda, sorta, sometimes works (sometimes the values show up in the text field, sometimes it doesn't display at all, sometimes the spacing within the text field is different):
func resizeTextView(_ textView: UITextView ) {
let currentHeight = textView.contentSize.height
let minHeight: CGFloat = 20.0
let maxHeight: CGFloat = 40.0
if currentHeight > maxHeight {
textView.frame.size.height = currentHeight
textView.isScrollEnabled = true
}
else if currentHeight < minHeight {
textView.frame.size.height = minHeight
textView.isScrollEnabled = false
}
else {
textView.frame.size.height = currentHeight
textView.isScrollEnabled = false
}
self.view.layoutIfNeeded()
}
I know this question has been asked an answered a dozen or more times, but none of the solutions are working for me (the above being two of the half dozen or more I have tried).
I think it is better to achieve this with Timer.
You solution above is that, UITextView's delegate methods triggers your height changing method.
Your changing method affects the UITextView's delegate method under the hood.
In other words, it is weird that you observe UITextView's property, then do something and affect the UITextView's property,
then the observation triggers again.
to achieve this with Timer, then the height changing events is from your timer source, not from Apple's UIKit
start editing, timer run
end editing, timer gone

Can't get UITextField to autoshrink the font

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...

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

Resize textField Based On Content

How can a textField be resized based on content while using auto-layout in an iOS application written in Swift?
The text field will resize as necessary to fit its content when the view loads as well as while the user is typing.
Ideally, the text field would stop resizing at a certain point, say, 6 lines, and become scrollable.
You have to use an UITextView instead of an UITextField.
Then, you can use the sizeThatFits method.
But first you have to know how high one line will be. You can get that information by using lineHeight:
var amountOfLinesToBeShown: CGFloat = 6
var maxHeight: CGFloat = yourTextview.font.lineHeight * amountOfLinesToBeShown
After that, just call the sizeThatFits method inside your viewDidLoad method and set the maxHeight (line * 6) as your textview height:
yourTextview.sizeThatFits(CGSizeMake(yourTextview.frame.size.width, maxHeight))
Swift 3
var textView : UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView = UITextView()
textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: textView.frame.size.height))
}

ContentOffset doesn't do anything to UITextView the first time

I'm trying to have a UIViewController to display some text centered vertically in a UITextView. When app is launched, the text is aligned to the top. But if I try to select some text, the text would then move to the center vertically. It seems like setting contentOffset doesn't do anything at the first time, unless there's some action to trigger it to readjust the layout (like selecting some text in my scenario).
Also when I log the values of height, size, contentHeight and topCorrect, the values from the first call is the same as the second call. So I'm getting the same value but UITextView somehow is not responding to the contentOffset the very first time.
I even tried moving the logic to viewDidLayoutSubviews() and viewDidAppear(). I had the same result. So I don't think it's a problem of having the logic in the wrong place.
I think some people have success with it on iOS 7 and Obj-C. I'm trying get it running on iOS 8 and Swift.
Any suggestion or help would be very much appreciated.
class PageContentViewController : UIViewController {
#IBOutlet weak var textView: UITextView!
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.textView.textContainerInset = UIEdgeInsetsMake(0, 16.0, 0, 16.0)
let height = self.textView.bounds.size.height
let size = CGSizeMake(self.textView.frame.width, CGFloat.max)
var contentHeight = self.textView.sizeThatFits(size).height
var topCorrect = (height - contentHeight * self.textView.zoomScale) / 2.0
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect;
self.textView.setContentOffset(CGPointMake(0, -topCorrect), animated: false)
}
}

Resources