通过 UITextView 高度限制字符
Limit characters by UITextView height
使用以下代码,我试图通过禁止用户在 UITextView
超出特定内容大小时输入字符来限制我的 UITextView
的高度。但问题是,使用当前代码,高度限制之后的最后一个字符无论如何都会被写入,这样一个字符就单独在它自己的行上结束,并且该行超出了高度限制。
如何修改我的代码,使文本不超过我的高度限制?
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
var frame:CGRect = textView.frame;
frame.size.height = textView.contentSize.height;
if(frame.size.height <= 33.0){
return true
}
else {
return false
}
}
您当前代码的问题在于,当您的文本视图尚未包含替换文本时,您正在使用 textView.contentSize.height
进行比较;因此,按照您的代码,如果文本视图的当前内容大小为 <= 33,它仍将允许您输入字符(即 return true
),以便那些 returned 字符实际上可以破坏文本视图的高度限制。
更新: 我不太喜欢我原来的答案,因为我认为 boundingRectWithSize
会提供更简洁的解决方案。但问题是,它对我不起作用,文本会超出行数限制……直到现在。诀窍是考虑文本容器的填充。
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// Combine the new text with the old
let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
// Create attributed version of the text
let attributedText = NSMutableAttributedString(string: combinedText)
attributedText.addAttribute(NSFontAttributeName, value: textView.font, range: NSMakeRange(0, attributedText.length))
// Get the padding of the text container
let padding = textView.textContainer.lineFragmentPadding
// Create a bounding rect size by subtracting the padding
// from both sides and allowing for unlimited length
let boundingSize = CGSizeMake(textView.frame.size.width - padding * 2, CGFloat.max)
// Get the bounding rect of the attributed text in the
// given frame
let boundingRect = attributedText.boundingRectWithSize(boundingSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
// Compare the boundingRect plus the top and bottom padding
// to the text view height; if the new bounding height would be
// less than or equal to the height limit, append the text
if (boundingRect.size.height + padding * 2 <= 33.0){
return true
}
else {
return false
}
}
原解:
要使用尽可能接近当前代码的解决方案来解决此问题,您可以复制文本视图,将新文本附加到旧文本,然后 return 仅当包含更新的文本视图时才为真新文本的大小小于高度限制,例如:
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// Combine the new text with the old
let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
// Create a duplicate of the text view with the same frame and font
let duplicateTextView = UITextView(frame: textView.frame)
duplicateTextView.font = textView.font
// Set the text view to contain the tentative new version of the text
duplicateTextView.text = combinedText
// Use sizeToFit in order to make the text view's height fit the text exactly
duplicateTextView.sizeToFit()
// Then use the duplicate text view's height for the comparison
if(duplicateTextView.frame.size.height <= 33.0){
return true
}
else {
return false
}
}
感谢@lyndsey-scott,下面是为 xcode 9.1 中的最新 sdk 更新的相同代码。进行了较小的编辑(将最大高度替换为变量)
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Combine the new text with the old
let combinedText = (textView.text as NSString).replacingCharacters(in: range, with: text)
// Create attributed version of the text
let attributedText = NSMutableAttributedString(string: combinedText)
let font = textView.font ?? UIFont.systemFont(ofSize: 12.0)
attributedText.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, attributedText.length))
// Get the padding of the text container
let padding = textView.textContainer.lineFragmentPadding
// Create a bounding rect size by subtracting the padding
// from both sides and allowing for unlimited length
let boundingSize = CGSize(width: textView.frame.size.width - padding * 2, height: CGFloat.greatestFiniteMagnitude)
// Get the bounding rect of the attributed text in the
// given frame
let boundingRect = attributedText.boundingRect(with: boundingSize, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil)
// Compare the boundingRect plus the top and bottom padding
// to the text view height; if the new bounding height would be
// less than or equal to the height limit, append the text
if (boundingRect.size.height + padding * 2 <= MyViewController.maximumHeaderHeight){
return true
} else {
return false
}
}
使用以下代码,我试图通过禁止用户在 UITextView
超出特定内容大小时输入字符来限制我的 UITextView
的高度。但问题是,使用当前代码,高度限制之后的最后一个字符无论如何都会被写入,这样一个字符就单独在它自己的行上结束,并且该行超出了高度限制。
如何修改我的代码,使文本不超过我的高度限制?
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
var frame:CGRect = textView.frame;
frame.size.height = textView.contentSize.height;
if(frame.size.height <= 33.0){
return true
}
else {
return false
}
}
您当前代码的问题在于,当您的文本视图尚未包含替换文本时,您正在使用 textView.contentSize.height
进行比较;因此,按照您的代码,如果文本视图的当前内容大小为 <= 33,它仍将允许您输入字符(即 return true
),以便那些 returned 字符实际上可以破坏文本视图的高度限制。
更新: 我不太喜欢我原来的答案,因为我认为 boundingRectWithSize
会提供更简洁的解决方案。但问题是,它对我不起作用,文本会超出行数限制……直到现在。诀窍是考虑文本容器的填充。
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// Combine the new text with the old
let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
// Create attributed version of the text
let attributedText = NSMutableAttributedString(string: combinedText)
attributedText.addAttribute(NSFontAttributeName, value: textView.font, range: NSMakeRange(0, attributedText.length))
// Get the padding of the text container
let padding = textView.textContainer.lineFragmentPadding
// Create a bounding rect size by subtracting the padding
// from both sides and allowing for unlimited length
let boundingSize = CGSizeMake(textView.frame.size.width - padding * 2, CGFloat.max)
// Get the bounding rect of the attributed text in the
// given frame
let boundingRect = attributedText.boundingRectWithSize(boundingSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
// Compare the boundingRect plus the top and bottom padding
// to the text view height; if the new bounding height would be
// less than or equal to the height limit, append the text
if (boundingRect.size.height + padding * 2 <= 33.0){
return true
}
else {
return false
}
}
原解:
要使用尽可能接近当前代码的解决方案来解决此问题,您可以复制文本视图,将新文本附加到旧文本,然后 return 仅当包含更新的文本视图时才为真新文本的大小小于高度限制,例如:
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// Combine the new text with the old
let combinedText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
// Create a duplicate of the text view with the same frame and font
let duplicateTextView = UITextView(frame: textView.frame)
duplicateTextView.font = textView.font
// Set the text view to contain the tentative new version of the text
duplicateTextView.text = combinedText
// Use sizeToFit in order to make the text view's height fit the text exactly
duplicateTextView.sizeToFit()
// Then use the duplicate text view's height for the comparison
if(duplicateTextView.frame.size.height <= 33.0){
return true
}
else {
return false
}
}
感谢@lyndsey-scott,下面是为 xcode 9.1 中的最新 sdk 更新的相同代码。进行了较小的编辑(将最大高度替换为变量)
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Combine the new text with the old
let combinedText = (textView.text as NSString).replacingCharacters(in: range, with: text)
// Create attributed version of the text
let attributedText = NSMutableAttributedString(string: combinedText)
let font = textView.font ?? UIFont.systemFont(ofSize: 12.0)
attributedText.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, attributedText.length))
// Get the padding of the text container
let padding = textView.textContainer.lineFragmentPadding
// Create a bounding rect size by subtracting the padding
// from both sides and allowing for unlimited length
let boundingSize = CGSize(width: textView.frame.size.width - padding * 2, height: CGFloat.greatestFiniteMagnitude)
// Get the bounding rect of the attributed text in the
// given frame
let boundingRect = attributedText.boundingRect(with: boundingSize, options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil)
// Compare the boundingRect plus the top and bottom padding
// to the text view height; if the new bounding height would be
// less than or equal to the height limit, append the text
if (boundingRect.size.height + padding * 2 <= MyViewController.maximumHeaderHeight){
return true
} else {
return false
}
}