UITextView's textContainer renders at the wrong frame when constraints are changed
up vote
0
down vote
favorite
All I want is to resize the UITextView
whenever you type/paste on it. It should be scrollable because I don't want the UITextView
to fill up the screen. It could be easily achievable with these few lines of codes.
@IBOutlet weak var mainTextView: UITextView!
@IBOutlet weak var mainTextViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.mainTextView.delegate = self
}
// This method is used for calculating what would be the UITextView's height
func heightOf(text: String, for textView: UITextView) -> CGFloat {
let nsstring: NSString = text as NSString
let boundingSize = nsstring.boundingRect(
with: CGSize(width: textView.frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: textView.font!],
context: nil).size
return ceil(boundingSize.height + textView.textContainerInset.top + textView.textContainerInset.bottom)
}
// The lines inside will change the UITextView's height
func textViewDidChange(_ textView: UITextView) {
let newString: String = textView.text ?? ""
let minHeight = self.heightOf(text: "", for: textView) // 1 line height
let maxHeight = self.heightOf(text: "nnnnn", for: textView) // 6 lines height
let contentHeight = self.heightOf(text: newString, for: textView) // height of the new string
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
}
This works perfectly well, except when the you paste a multi-line text.
To solve the pasting issue, various SO questions suggested that I either create a subclass of UITextView
to override the paste(_:)
method or I use the textView(_: shouldChangeTextIn....)
delegate method. After a few experiments with both the best answer was to use the shouldChangeTextIn
method which resulted my code into this
// I replaced `textViewDidChange(_ textView: UITextView)` with this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newString: String = ((textView.text ?? "") as NSString).replacingCharacters(in: range, with: text)
let minHeight = self.heightOf(text: "", for: textView)
let maxHeight = self.heightOf(text: "nnnnn", for: textView)
let contentHeight = self.heightOf(text: newString, for: textView)
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
return true
}
Now what should happen is that when the you paste text the UITextView
should look like this. (The pasted string is "AnAnAnAnA" or 5 lines of just A's)
However it becomes like this
As you can see from the screenshots, the textContainer's frame is at the wrong position. Now the weird thing about this is that it seems to only happen when you're pasting at an empty UITextView
.
I've tried setting and resetting the UITextView
's frame.size, I've tried manually setting the NSTextContainer
's size, and some other hacky solutions but I just can't seem to fix it. How can I solve this?
Note:
OS Support: iOS 8.xx - iOS 12.xx
Xcode: v10.10
Swift: 3 and 4 (I tried on both)
PS: yes I have already been on other SO questions such ones listed on the bottom and a few others
- TextContainer isn't resizing while changing bounds of UITextView
- UITextView's text going beyond bounds
- UITextView stange animation glitch on paste action (iOS11)
- How to calculate TextView height base on text
ios swift uitextview
add a comment |
up vote
0
down vote
favorite
All I want is to resize the UITextView
whenever you type/paste on it. It should be scrollable because I don't want the UITextView
to fill up the screen. It could be easily achievable with these few lines of codes.
@IBOutlet weak var mainTextView: UITextView!
@IBOutlet weak var mainTextViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.mainTextView.delegate = self
}
// This method is used for calculating what would be the UITextView's height
func heightOf(text: String, for textView: UITextView) -> CGFloat {
let nsstring: NSString = text as NSString
let boundingSize = nsstring.boundingRect(
with: CGSize(width: textView.frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: textView.font!],
context: nil).size
return ceil(boundingSize.height + textView.textContainerInset.top + textView.textContainerInset.bottom)
}
// The lines inside will change the UITextView's height
func textViewDidChange(_ textView: UITextView) {
let newString: String = textView.text ?? ""
let minHeight = self.heightOf(text: "", for: textView) // 1 line height
let maxHeight = self.heightOf(text: "nnnnn", for: textView) // 6 lines height
let contentHeight = self.heightOf(text: newString, for: textView) // height of the new string
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
}
This works perfectly well, except when the you paste a multi-line text.
To solve the pasting issue, various SO questions suggested that I either create a subclass of UITextView
to override the paste(_:)
method or I use the textView(_: shouldChangeTextIn....)
delegate method. After a few experiments with both the best answer was to use the shouldChangeTextIn
method which resulted my code into this
// I replaced `textViewDidChange(_ textView: UITextView)` with this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newString: String = ((textView.text ?? "") as NSString).replacingCharacters(in: range, with: text)
let minHeight = self.heightOf(text: "", for: textView)
let maxHeight = self.heightOf(text: "nnnnn", for: textView)
let contentHeight = self.heightOf(text: newString, for: textView)
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
return true
}
Now what should happen is that when the you paste text the UITextView
should look like this. (The pasted string is "AnAnAnAnA" or 5 lines of just A's)
However it becomes like this
As you can see from the screenshots, the textContainer's frame is at the wrong position. Now the weird thing about this is that it seems to only happen when you're pasting at an empty UITextView
.
I've tried setting and resetting the UITextView
's frame.size, I've tried manually setting the NSTextContainer
's size, and some other hacky solutions but I just can't seem to fix it. How can I solve this?
Note:
OS Support: iOS 8.xx - iOS 12.xx
Xcode: v10.10
Swift: 3 and 4 (I tried on both)
PS: yes I have already been on other SO questions such ones listed on the bottom and a few others
- TextContainer isn't resizing while changing bounds of UITextView
- UITextView's text going beyond bounds
- UITextView stange animation glitch on paste action (iOS11)
- How to calculate TextView height base on text
ios swift uitextview
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
All I want is to resize the UITextView
whenever you type/paste on it. It should be scrollable because I don't want the UITextView
to fill up the screen. It could be easily achievable with these few lines of codes.
@IBOutlet weak var mainTextView: UITextView!
@IBOutlet weak var mainTextViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.mainTextView.delegate = self
}
// This method is used for calculating what would be the UITextView's height
func heightOf(text: String, for textView: UITextView) -> CGFloat {
let nsstring: NSString = text as NSString
let boundingSize = nsstring.boundingRect(
with: CGSize(width: textView.frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: textView.font!],
context: nil).size
return ceil(boundingSize.height + textView.textContainerInset.top + textView.textContainerInset.bottom)
}
// The lines inside will change the UITextView's height
func textViewDidChange(_ textView: UITextView) {
let newString: String = textView.text ?? ""
let minHeight = self.heightOf(text: "", for: textView) // 1 line height
let maxHeight = self.heightOf(text: "nnnnn", for: textView) // 6 lines height
let contentHeight = self.heightOf(text: newString, for: textView) // height of the new string
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
}
This works perfectly well, except when the you paste a multi-line text.
To solve the pasting issue, various SO questions suggested that I either create a subclass of UITextView
to override the paste(_:)
method or I use the textView(_: shouldChangeTextIn....)
delegate method. After a few experiments with both the best answer was to use the shouldChangeTextIn
method which resulted my code into this
// I replaced `textViewDidChange(_ textView: UITextView)` with this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newString: String = ((textView.text ?? "") as NSString).replacingCharacters(in: range, with: text)
let minHeight = self.heightOf(text: "", for: textView)
let maxHeight = self.heightOf(text: "nnnnn", for: textView)
let contentHeight = self.heightOf(text: newString, for: textView)
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
return true
}
Now what should happen is that when the you paste text the UITextView
should look like this. (The pasted string is "AnAnAnAnA" or 5 lines of just A's)
However it becomes like this
As you can see from the screenshots, the textContainer's frame is at the wrong position. Now the weird thing about this is that it seems to only happen when you're pasting at an empty UITextView
.
I've tried setting and resetting the UITextView
's frame.size, I've tried manually setting the NSTextContainer
's size, and some other hacky solutions but I just can't seem to fix it. How can I solve this?
Note:
OS Support: iOS 8.xx - iOS 12.xx
Xcode: v10.10
Swift: 3 and 4 (I tried on both)
PS: yes I have already been on other SO questions such ones listed on the bottom and a few others
- TextContainer isn't resizing while changing bounds of UITextView
- UITextView's text going beyond bounds
- UITextView stange animation glitch on paste action (iOS11)
- How to calculate TextView height base on text
ios swift uitextview
All I want is to resize the UITextView
whenever you type/paste on it. It should be scrollable because I don't want the UITextView
to fill up the screen. It could be easily achievable with these few lines of codes.
@IBOutlet weak var mainTextView: UITextView!
@IBOutlet weak var mainTextViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.mainTextView.delegate = self
}
// This method is used for calculating what would be the UITextView's height
func heightOf(text: String, for textView: UITextView) -> CGFloat {
let nsstring: NSString = text as NSString
let boundingSize = nsstring.boundingRect(
with: CGSize(width: textView.frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: textView.font!],
context: nil).size
return ceil(boundingSize.height + textView.textContainerInset.top + textView.textContainerInset.bottom)
}
// The lines inside will change the UITextView's height
func textViewDidChange(_ textView: UITextView) {
let newString: String = textView.text ?? ""
let minHeight = self.heightOf(text: "", for: textView) // 1 line height
let maxHeight = self.heightOf(text: "nnnnn", for: textView) // 6 lines height
let contentHeight = self.heightOf(text: newString, for: textView) // height of the new string
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
}
This works perfectly well, except when the you paste a multi-line text.
To solve the pasting issue, various SO questions suggested that I either create a subclass of UITextView
to override the paste(_:)
method or I use the textView(_: shouldChangeTextIn....)
delegate method. After a few experiments with both the best answer was to use the shouldChangeTextIn
method which resulted my code into this
// I replaced `textViewDidChange(_ textView: UITextView)` with this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let newString: String = ((textView.text ?? "") as NSString).replacingCharacters(in: range, with: text)
let minHeight = self.heightOf(text: "", for: textView)
let maxHeight = self.heightOf(text: "nnnnn", for: textView)
let contentHeight = self.heightOf(text: newString, for: textView)
self.mainTextViewHeightConstraint.constant = min(max(minHeight, contentHeight), maxHeight)
return true
}
Now what should happen is that when the you paste text the UITextView
should look like this. (The pasted string is "AnAnAnAnA" or 5 lines of just A's)
However it becomes like this
As you can see from the screenshots, the textContainer's frame is at the wrong position. Now the weird thing about this is that it seems to only happen when you're pasting at an empty UITextView
.
I've tried setting and resetting the UITextView
's frame.size, I've tried manually setting the NSTextContainer
's size, and some other hacky solutions but I just can't seem to fix it. How can I solve this?
Note:
OS Support: iOS 8.xx - iOS 12.xx
Xcode: v10.10
Swift: 3 and 4 (I tried on both)
PS: yes I have already been on other SO questions such ones listed on the bottom and a few others
- TextContainer isn't resizing while changing bounds of UITextView
- UITextView's text going beyond bounds
- UITextView stange animation glitch on paste action (iOS11)
- How to calculate TextView height base on text
ios swift uitextview
ios swift uitextview
edited Nov 9 at 2:30
asked Nov 8 at 11:05
Zonily Jame
1,4921925
1,4921925
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
You can ignore all the code for calculating height and use the set the textview attribute scrolling Enabled = false
the textview will adjust it self to fit with the text content
image1
then change the code as you want
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.text = "AnAnAnAnA"
}
The result will be like this
image2
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
You can ignore all the code for calculating height and use the set the textview attribute scrolling Enabled = false
the textview will adjust it self to fit with the text content
image1
then change the code as you want
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.text = "AnAnAnAnA"
}
The result will be like this
image2
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
add a comment |
up vote
0
down vote
You can ignore all the code for calculating height and use the set the textview attribute scrolling Enabled = false
the textview will adjust it self to fit with the text content
image1
then change the code as you want
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.text = "AnAnAnAnA"
}
The result will be like this
image2
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
add a comment |
up vote
0
down vote
up vote
0
down vote
You can ignore all the code for calculating height and use the set the textview attribute scrolling Enabled = false
the textview will adjust it self to fit with the text content
image1
then change the code as you want
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.text = "AnAnAnAnA"
}
The result will be like this
image2
You can ignore all the code for calculating height and use the set the textview attribute scrolling Enabled = false
the textview will adjust it self to fit with the text content
image1
then change the code as you want
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.text = "AnAnAnAnA"
}
The result will be like this
image2
answered Nov 8 at 14:10
Hussam
11
11
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
add a comment |
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
Nope, that doesn't solve my problem, let me edit my question so it can be clearer.
– Zonily Jame
Nov 9 at 2:25
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53206469%2fuitextviews-textcontainer-renders-at-the-wrong-frame-when-constraints-are-chang%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown