解決しました!( https://github.com/jerrykrinock/CategoriesObjC/blob/master/NS(Attributed)String%2BGeometrics/NS(Attributed)String%2BGeometrics.mに触発されました)
通常、 Appleのドキュメントを読むと役に立ちます。Appleは、これらすべてのテキストレイアウトを、あらゆる種類の複雑なエッジケースを処理するのに十分強力になるように設計しました。これは、非常に役立つ場合とそうでない場合があります。
まず、単語の区切りで行を折り返すようにテキストフィールドを設定したので、実際には複数の行が表示されます。(サンプルコードにはifステートメントも含まれているため、ラッピングがオフになっている場合は何も実行されませんでした)。
NSTextView
これの秘訣は、テキストが編集されているときに、「フィールドエディタ」によって印刷されることに注意することでした。これは、が所有する重量のあるオブジェクトであり、現在「ファーストレスポンダー」(選択済み)であるNSWindow
ものによって再利用されます。NSTextField
には、テキストをレイアウトするためNSTextView
の単一のNSTextContainer
(テキストが入る長方形)があります。NSLayoutManager
テキストフィールドの新しい高さを取得するために、レイアウトマネージャーにどのくらいのスペースを使いたいかを尋ねることができます。
もう1つのトリックは、NSText
デリゲートメソッドをオーバーライドし- (void)textDidChange:(NSNotification *)notification
て、テキストが変更されたときに固有のコンテンツサイズを無効にすることでした(したがって、returnキーを押して変更をコミットしたときに更新を待つだけではありません)。
最初に提案したように使用しなかった理由はcellSizeForBounds
、問題を解決できなかったためです。セルの固有のコンテンツサイズを無効にしてもcellSizeForBounds:
、古いサイズを返し続けました。
GitHubでサンプルプロジェクトを見つけます。
@interface TSTTextGrowth()
{
BOOL _hasLastIntrinsicSize;
BOOL _isEditing;
NSSize _lastIntrinsicSize;
}
@end
@implementation TSTTextGrowth
- (void)textDidBeginEditing:(NSNotification *)notification
{
[super textDidBeginEditing:notification];
_isEditing = YES;
}
- (void)textDidEndEditing:(NSNotification *)notification
{
[super textDidEndEditing:notification];
_isEditing = NO;
}
- (void)textDidChange:(NSNotification *)notification
{
[super textDidChange:notification];
[self invalidateIntrinsicContentSize];
}
-(NSSize)intrinsicContentSize
{
NSSize intrinsicSize = _lastIntrinsicSize;
// Only update the size if we’re editing the text, or if we’ve not set it yet
// If we try and update it while another text field is selected, it may shrink back down to only the size of one line (for some reason?)
if(_isEditing || !_hasLastIntrinsicSize)
{
intrinsicSize = [super intrinsicContentSize];
// If we’re being edited, get the shared NSTextView field editor, so we can get more info
NSText *fieldEditor = [self.window fieldEditor:NO forObject:self];
if([fieldEditor isKindOfClass:[NSTextView class]])
{
NSTextView *textView = (NSTextView *)fieldEditor;
NSRect usedRect = [textView.textContainer.layoutManager usedRectForTextContainer:textView.textContainer];
usedRect.size.height += 5.0; // magic number! (the field editor TextView is offset within the NSTextField. It’s easy to get the space above (it’s origin), but it’s difficult to get the default spacing for the bottom, as we may be changing the height
intrinsicSize.height = usedRect.size.height;
}
_lastIntrinsicSize = intrinsicSize;
_hasLastIntrinsicSize = YES;
}
return intrinsicSize;
}
@end
最後に、私は実際に自動レイアウトを自分で使用したことはありません。デモはすばらしいように見えますが、実際に自分で試してみると、正しく機能させることができず、事態がさらに複雑になります。ただし、この場合、実際には多くの作業を節約できたと思います。これがないと-intrinsicContentSize
、フレームは存在しません。フレームを自分で設定して、新しい原点と新しいサイズを計算する必要があります(あまりにも多くありません)。難しいですが、コードが増えます)。