テキストビューのフレームによってテキストがラップされるとき、テキストがラップされているかどうかを識別するための区切り文字があるかどうかを知りたいと思いました。
たとえば、テキストビューの幅が50ピクセルで、テキストがそれを超える場合、テキストが次の行に折り返されます。
テキストビューの行数を数えたかったのですが。現在、「\ n」と「\ r」は私を助けていません。
私のコードは:
NSCharacterSet *aCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"\n\r"];
NSArray *myArray = [textViewText componentsSeparatedByCharactersInSet:aCharacterSet];
NSLog(@"%d",[myArray count]);
このバリエーションは、行の折り返し方法とUITextView
の最大サイズを考慮しており、より正確な高さを出力する場合があります。たとえば、テキストが収まらない場合は表示サイズに切り捨てられ、単語全体をラップすると(デフォルト)、それ以外の場合よりも行数が増える可能性があります。
UIFont *font = [UIFont boldSystemFontOfSize:11.0];
CGSize size = [string sizeWithFont:font
constrainedToSize:myUITextView.frame.size
lineBreakMode:UILineBreakModeWordWrap]; // default mode
float numberOfLines = size.height / font.lineHeight;
lineHeight
プロパティとフォントlineHeight
を使用する必要があります。
Objective-C
int numLines = txtview.contentSize.height / txtview.font.lineHeight;
スウィフト
let numLines = (txtview.contentSize.height / txtview.font.lineHeight) as? Int
正しい行数を取得しています。それがあなたにも役立つことを願っています。
スウィフト3:
let layoutManager:NSLayoutManager = textView.layoutManager
let numberOfGlyphs = layoutManager.numberOfGlyphs
var numberOfLines = 0
var index = 0
var lineRange:NSRange = NSRange()
while (index < numberOfGlyphs) {
layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange);
numberOfLines = numberOfLines + 1
}
print(numberOfLines)
Swift拡張:
@himanshu padia回答の使用
_//MARK: - UITextView
extension UITextView{
func numberOfLines() -> Int{
if let fontUnwrapped = self.font{
return Int(self.contentSize.height / fontUnwrapped.lineHeight)
}
return 0
}
}
_
使用法:yourTextView.numberOfLines()
何らかの理由でテキストビューのフォントがnilの場合、戻り値はゼロになることに注意してください。
私はこの問題の完璧な解決策をAppleの Text Layout Programming Guide で見つけました。 Appleが提供するソリューションは次のとおりです。
NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index;
unsigned numberOfGlyphs = [layoutManager numberOfGlyphs];
NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
(void) [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange:&lineRange];
index = NSMaxRange(lineRange);
}
これは、UITextViewの拡張機能に簡単に書き込むことも、UITextViewオブジェクトをパラメーターとして受け取るスタンドアロンメソッドとして書き込むこともできます。
Swift 4バージョンのLuke Chase'sanswer
let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
var index = 0, numberOfLines = 0
var lineRange = NSRange(location: NSNotFound, length: 0)
while index < numberOfGlyphs {
textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
TextView.textContainerInsetを考慮する必要があります。また、行番号は間違いなく整数であるため、計算された値を丸める必要があります。
float rawLineNumber = (textView.contentSize.height - textView.textContainerInset.top - textView.textContainerInset.bottom) / textView.font.lineHeight;
int finalLineNumber = round(rawLineNumber)
実際の場合、次の結果が表示されることがありますrawLineNumber = 3.008099 finalLineNumber = 3(3行)
func numberOfLines(textView: UITextView) -> Int {
let layoutManager = textView.layoutManager
let numberOfGlyphs = layoutManager.numberOfGlyphs
var lineRange: NSRange = NSMakeRange(0, 1)
var index = 0
var numberOfLines = 0
while index < numberOfGlyphs {
layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
return numberOfLines
}
私のためにうまくいく
これを使用します(_text_vはテキストビューです):
-(NSInteger) linesCount {
return _text_v.contentSize.height/_text_v.font.lineHeight;
}
入力TextView(チャットのテキスト入力ボックスなど)の行数をリアルタイムで計算することに多くの時間を費やしましたが、そのような場合に機能する唯一の解決策は、Luke Chaseの(何らかの理由でframe.heightアプローチ)です。 textViewに入力された3番目または4番目の文字のみが更新されるように見えるため、正確ではありません)。
ただし、コメンターが述べたように、ユーザーが生成した改行(「\ n」またはキーボードのリターンプレス)が適切に考慮されないという小さなバグがあります。さらに奇妙なことに、そのような最初の改行が「欠落」しているだけで、後続の改行は正しくキャプチャされます(4回行に移動すると、最初の改行がないことが3行だけ返されます)。
したがって、そのバグを回避するために、最初の改行(文字「\ n」)を記録して、gliphメソッドが返す行数に手動で行を追加します。
与えるコードでは:
func offSetTableViewIfNeeded() {
let numberOfGlyphs = textView.layoutManager.numberOfGlyphs
var index : Int = 0
var lineRange = NSRange(location: NSNotFound, length: 0)
var currentNumOfLines : Int = 0
var numberOfParagraphJump : Int = 0
while index < numberOfGlyphs {
textView.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
currentNumOfLines += 1
// Observing whether user went to line and if it's the first such line break, accounting for it.
if textView.text.last == "\n", numberOfParagraphJump == 0 {
numberOfParagraphJump = 1
}
}
currentNumOfLines += numberOfParagraphJump
print("Number of lines is:", currentNumOfLines)
これが入力textViewの非常に奇妙な動作に苦労している他の人に役立つことを願っています(なぜAppleが箱から出して#of lineメソッドを提供しないのか理解できません!))。
Swift 5.0
extension UITextView {
func sizeFit(width: CGFloat) -> CGSize {
let fixedWidth = width
let newSize = sizeThatFits(CGSize(width: fixedWidth, height: .greatestFiniteMagnitude))
return CGSize(width: fixedWidth, height: newSize.height)
}
func numberOfLine() -> Int {
let size = self.sizeFit(width: self.bounds.width)
let numLines = Int(size.height / (self.font?.lineHeight ?? 1.0))
return numLines
}
}
改善および更新Luke Chase'sanswer to Swift 5、XCode 11、iOS 13 toテキストビューの行数を取得し、テーブルビューのセルの高さを自動サイズ変更します。
1)セルの高さが静的なストーリーボードを使用して、好きなようにデザインできます。
2)viewDidLoadで、推定行の高さとtextViewデリゲートを追加します。
override func viewDidLoad() {
super.viewDidLoad()
quoteTextView.delegate = self
tableView.estimatedRowHeight = 142
}
3)heightForRowAtのテーブルビューデリゲートを追加します。
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
4)UITextViewDelegateに準拠し、ユーザーがテキストを入力するときにリッスンします。
extension ViewController: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
// Refresh tableView cell
if textView.numberOfLines > 2 { // textView in storyboard has two lines, so we match the design
// Animated height update
DispatchQueue.main.async {
self.tableView?.beginUpdates()
self.tableView?.endUpdates()
}
}
}
}
5)UITextView拡張機能を追加して、冗長なコードを回避し、アプリ全体で使用できるようにします。
extension UITextView {
var numberOfLines: Int {
// Get number of lines
let numberOfGlyphs = self.layoutManager.numberOfGlyphs
var index = 0, numberOfLines = 0
var lineRange = NSRange(location: NSNotFound, length: 0)
while index < numberOfGlyphs {
self.layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
return numberOfLines
}
}
プレビュー
NSLayoutManager
を使用してみてください:
NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index, numberOfGlyphs =
[layoutManager numberOfGlyphs];
NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
(void) [layoutManager lineFragmentRectForGlyphAtIndex:index
effectiveRange:&lineRange];
index = NSMaxRange(lineRange);
}