我的屏幕上有一个UITextView,用户应该只填充两行,当第二行中的用户返回键应该变为完成。
如何在UITextView中限制行的数量? 我搜索了很多,没有结果有用!
我找到了Swift的答案:
locationNoteTextView.textContainer.maximumNumberOfLines = 2
self.locationNoteTextView.textContainer.lineBreakMode = NSLineBreakMode.ByClipping
它不起作用,通过这种方式用户可以输入无限字符,但在屏幕上查看的内容只有两行!
因此,如果您尝试打印textView文本,您将找到灾难文本。
答案 0 :(得分:15)
您需要实施textView:shouldChangeTextInRange:replacementText:
。只要文本要更改,就会调用此方法。您可以使用其text属性访问文本视图的当前内容。
使用[textView.text stringByReplacingCharactersInRange:range withString:replacementText]
从传递的范围和替换文本构造新内容。
然后,您可以计算行数并返回YES
以允许更改,或NO
拒绝更改。
编辑:在OP请求中:
<强>夫特:强>
func sizeOfString (string: String, constrainedToWidth width: Double, font: UIFont) -> CGSize {
return (string as NSString).boundingRectWithSize(CGSize(width: width, height: DBL_MAX),
options: NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: [NSFontAttributeName: font],
context: nil).size
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
var textWidth = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset))
textWidth -= 2.0 * textView.textContainer.lineFragmentPadding;
let boundingRect = sizeOfString(newText, constrainedToWidth: Double(textWidth), font: textView.font!)
let numberOfLines = boundingRect.height / textView.font!.lineHeight;
return numberOfLines <= 2;
}
<强>的OBJ-C 强>
- (CGSize) sizeOfString:(NSString*)str constrainedToWidth:(CGFloat)width andFont:(UIFont*)font
{
return [str boundingRectWithSize:CGSizeMake(width, DBL_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: font}
context:nil].size;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
CGFloat textWidth = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset));
textWidth -= 2.0 * textView.textContainer.lineFragmentPadding;
CGSize boundingRect = [self sizeOfString:newText constrainedToWidth:textWidth andFont:textView.font];
int numberOfLines = boundingRect.height / textView.font.lineHeight;
return numberOfLines <= 2;
}
答案 1 :(得分:11)
适用于iOS 7 +
textView.textContainer.maximumNumberOfLines = 10;
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
OR
textView.textContainer.maximumNumberOfLines = 10;
[textView.layoutManager textContainerChangedGeometry:textView.textContainer];
答案 2 :(得分:1)
如果有人想要实时行号计数,这就是你用RxSwift&amp; RxCocoa
let disposeBag = DisposeBag()
textView.rx_text.asDriver().driveNext { text in
let text = text as NSString
var textWidth: CGFloat = CGRectGetWidth(UIEdgeInsetsInsetRect(self.textView.frame, self.textView.textContainerInset))
textWidth -= 2.0 * self.textView.textContainer.lineFragmentPadding
let textAttributes = [NSFontAttributeName: UIFont(name: “Set your font here”, size: 26.0)!]
let boundingRect: CGRect = text.boundingRectWithSize(CGSizeMake(textWidth, 0), options: [NSStringDrawingOptions.UsesLineFragmentOrigin, NSStringDrawingOptions.UsesFontLeading], attributes: textAttributes, context: nil)
let font = UIFont(name: “Set your font here”, size: 26.0)
guard let lineHeight = font?.lineHeight else {return}
let numberOfLines = CGRectGetHeight(boundingRect) / lineHeight
if numberOfLines <= 2 {
self.textView.typingAttributes = [NSFontAttributeName: UIFont(name: “Set your font here”, size: 26.0)!, NSForegroundColorAttributeName: “Set your color here”]
} else {
self.textView.typingAttributes = [NSFontAttributeName: UIFont(name: “Set your font here”, size: 18.0)!, NSForegroundColorAttributeName: “Set your color here”]
}
}.addDisposableTo(disposeBag)
答案 3 :(得分:0)
这是@Abhinav的答案,但是在 Swift
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
let newText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: text)
let textAttributes = [NSFontAttributeName: textView.font]
var textWidth: CGFloat = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset))
textWidth -= 2.0 * textView.textContainer.lineFragmentPadding
let boundingRect: CGRect = newText.boundingRectWithSize(CGSizeMake(textWidth, 0), options: NSStringDrawingOptions.UsesLineFragmentOrigin|NSStringDrawingOptions.UsesFontLeading, attributes: textAttributes, context: nil)
var numberOfLines = CGRectGetHeight(boundingRect) / textView.font.lineHeight;
return numberOfLines <= 2;
}
答案 4 :(得分:0)
这是@ Abhinav的答案更新 Swift 3
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
guard maxLines > 0 else {
return true
}
let newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
let textAttributes = [NSAttributedStringKey.font : textView.font!]
var textWidth: CGFloat = UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset).width
textWidth -= 2.0 * textView.textContainer.lineFragmentPadding
let boundingRect: CGRect = newText.boundingRect(with: CGSize(width: textWidth, height: 0), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: textAttributes, context: nil)
let numberOfLines = Int(floor(boundingRect.height / textView.font!.lineHeight))
return numberOfLines <= maxLines
}
其中 maxLines 是您要将textView限制为的行数。如果它是0那么无限数量的行。
答案 5 :(得分:0)
我将@Abhinav代码更新为Swift 5,还增加了对限制字符数的支持。
import UIKit
class ViewController: UIViewController {
@IBOutlet private var textView: UITextView!
private let maxNumberOfLines = 4
private let maxCharactersCount = 100
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
}
}
extension ViewController: UITextViewDelegate {
private func textView(_ textView: UITextView, newText: String, underLineLimit: Int) -> Bool {
guard let textViewFont = textView.font else {
return false
}
let rect = textView.frame.inset(by: textView.textContainerInset)
let textWidth = rect.width - 2.0 * textView.textContainer.lineFragmentPadding
let boundingRect = newText.size(constrainedToWidth: textWidth,
font: textViewFont)
let numberOfLines = boundingRect.height / textViewFont.lineHeight
let underLimit = Int(numberOfLines) <= underLineLimit
return underLimit
}
func textView(_ textView: UITextView,
shouldChangeTextIn range: NSRange,
replacementText text: String) -> Bool {
let newText = textView.text.replacingCharacters(in: range, with: text)
let underLineLimit = self.textView(textView, newText: newText, underLineLimit: maxNumberOfLines)
let underCharacterLimit = newText.count <= maxCharactersCount
return underLineLimit && underCharacterLimit
}
}
extension String {
func replacingCharacters(in range: NSRange, with string: String) -> String {
let currentNSString = self as NSString
return currentNSString.replacingCharacters(in: range, with: string)
}
func size(constrainedToWidth width: CGFloat, font: UIFont) -> CGSize {
let nsString = self as NSString
let boundingSize = CGSize(width: width, height: .greatestFiniteMagnitude)
return nsString
.boundingRect(with: boundingSize,
options: .usesLineFragmentOrigin,
attributes: [.font: font],
context: nil)
.size
}
}
答案 6 :(得分:-3)
在下面找到Abhinav答案的Objective C版本:
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
CGFloat textWidth = CGRectGetWidth(UIEdgeInsetsInsetRect(textView.frame, textView.textContainerInset));
textWidth -= 2.0 * textView.textContainer.lineFragmentPadding;
CGSize boundingRect = [self sizeOfString:newText constrainedToWidth:textWidth font:textView.font];
NSInteger numberOfLines = boundingRect.height / textView.font.lineHeight;
return numberOfLines <= 2;
}
-(CGSize)sizeOfString:(NSString *)string constrainedToWidth:(double)width font:(UIFont *)font
{
return [string boundingRectWithSize:CGSizeMake(width, DBL_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font} context:nil].size;
}