私は受け入れられた答えを使用しています here 何年もの間。
IOS 7では、テキストコンテンツに関係なく、contentSize.heightはframe.height-8になります。
IOS 7で高さを調整する作業方法は何ですか?
私はこの最小限のコード変更を好みます:addSubview
の後で、height
のframe
を取得する前に、これらの2行を追加するだけです
...
[scrollView1 addSubview: myTextView];
[myTextView sizeToFit]; //added
[myTextView layoutIfNeeded]; //added
CGRect frame = myTextView.frame;
...
これは、iOS 6との後方互換性がテストされています。NOTE幅を縮小ラップします。高さに関心があり、幅が固定されている場合は、新しい高さを取得して元の幅を設定するだけで、iOS 6と7の両方で以前と同じように機能します。
(推測:iOS 7にも収まるサイズになりますが、レイアウトは後でまたは別のスレッドで更新され、これによりフレームが時間内に更新されるようにレイアウトがすぐに強制されます同じスレッドで数行後に高さの値を使用するため。)
注:
1)この方法で外部コンテナのサイズ変更を実装する場合としない場合があります。ただし、これは一般的なスニペットのようで、プロジェクトで使用しました。
2)sizeToFit
はiOS 7で期待どおりに機能するようであるため、時期尚早のaddSubViewは必要ないでしょう。まだiOS 6で動作するかどうかは、私がテストしていません。
3)推測:余分なlayoutIfNeeded
ミッドスレッドはコストがかかる場合があります。私が見る代替案は、外部コンテナのサイズ変更が別のレイアウト更新を引き起こすレイアウトコールバックで外部コンテナのサイズを変更することです(OSがレイアウトが必要かどうかを決定するかどうかに応じて起動または非起動)。両方の更新を他のレイアウト更新と組み合わせて、より効率的にすることができます。あなたがdoそのような解決策を持っていて、あなたがそれを示すことができる場合isより効率的に、答えとしてそれを追加し、私はそれをここで必ず言及するでしょう。
自動レイアウトを使用しているので、[textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)].height
の値を使用して、constant
の高さtextView
のUILayoutConstraint
を更新します。
ファッジファクターを排除するmadmikの回答の適応バージョンを使用します。
- (CGFloat)measureHeightOfUITextView:(UITextView *)textView
{
if ([textView respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
{
// This is the code for iOS 7. contentSize no longer returns the correct value, so
// we have to calculate it.
//
// This is partly borrowed from HPGrowingTextView, but I've replaced the
// magic fudge factors with the calculated values (having worked out where
// they came from)
CGRect frame = textView.bounds;
// Take account of the padding added around the text.
UIEdgeInsets textContainerInsets = textView.textContainerInset;
UIEdgeInsets contentInsets = textView.contentInset;
CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + textView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right;
CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom;
frame.size.width -= leftRightPadding;
frame.size.height -= topBottomPadding;
NSString *textToMeasure = textView.text;
if ([textToMeasure hasSuffix:@"\n"])
{
textToMeasure = [NSString stringWithFormat:@"%@-", textView.text];
}
// NSString class method: boundingRectWithSize:options:attributes:context is
// available only on ios7.0 sdk.
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
NSDictionary *attributes = @{ NSFontAttributeName: textView.font, NSParagraphStyleAttributeName : paragraphStyle };
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding);
return measuredHeight;
}
else
{
return textView.contentSize.height;
}
}
他の回答に基づいて、私はそれを機能させました(Swiftで)。これにより、改行文字に関する問題が解決されます。
textView.sizeToFit()
textView.layoutIfNeeded()
let height = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max)).height
textView.contentSize.height = height
自動レイアウトが必要です。
自動レイアウトを使用している場合、コンテンツに合わせてテキストビューの高さを自動調整する簡単なUITextView
サブクラスを作成できます。
@interface ContentHeightTextView : UITextView
@end
@interface ContentHeightTextView ()
@property (nonatomic, strong) NSLayoutConstraint *heightConstraint;
@end
@implementation ContentHeightTextView
- (void)layoutSubviews
{
[super layoutSubviews];
CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)];
if (!self.heightConstraint) {
self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height];
[self addConstraint:self.heightConstraint];
}
self.heightConstraint.constant = size.height;
[super layoutSubviews];
}
@end
もちろん、テキストビューの幅と位置は、プログラムの他の場所で構成された追加の制約によって定義する必要があります。
このカスタムテキストビューをIBで作成する場合、Xcodeを満たすためにテキストビューに高さの制約を与えます。 IBで作成された高さの制約が単なるプレースホルダーであることを確認してください(つまり、「ビルド時に削除」というボックスにチェックを入れてください)。
UITextView
サブクラスを実装する別の方法は次のとおりです(この実装はベストプラクティスとして認定される場合があります)。
@interface ContentHeightTextView ()
@property (nonatomic, strong) NSLayoutConstraint *heightConstraint;
@end
@implementation ContentHeightTextView
- (void)layoutSubviews
{
[super layoutSubviews];
[self setNeedsUpdateConstraints];
}
- (void)updateConstraints
{
CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)];
if (!self.heightConstraint) {
self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height];
[self addConstraint:self.heightConstraint];
}
self.heightConstraint.constant = size.height;
[super updateConstraints];
}
@end
自動レイアウトを使用している場合、固有の高さを追加する次のUITextViewサブクラスを使用できます。
@implementation SelfSizingTextView
- (void)setText:(NSString *)text
{
[super setText:text];
[self invalidateIntrinsicContentSize];
}
- (void)setFont:(UIFont *)font
{
[super setFont:font];
[self invalidateIntrinsicContentSize];
}
- (CGSize)intrinsicContentSize
{
CGFloat width = self.frame.size.width;
CGSize size = [self sizeThatFits:CGSizeMake(width, MAXFLOAT)];
return CGSizeMake(UIViewNoIntrinsicMetric, size.height);
}
@end
この方法はうまくいくようです。
// Code from Apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
- (CGFloat)measureHeight
{
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
{
CGRect frame = internalTextView.bounds;
CGSize fudgeFactor;
// The padding added around the text on iOS6 and iOS7 is different.
fudgeFactor = CGSizeMake(10.0, 16.0);
frame.size.height -= fudgeFactor.height;
frame.size.width -= fudgeFactor.width;
NSMutableAttributedString* textToMeasure;
if(internalTextView.attributedText && internalTextView.attributedText.length > 0){
textToMeasure = [[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
}
else{
textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
[textToMeasure addAttribute:NSFontAttributeName value:internalTextView.font range:NSMakeRange(0, textToMeasure.length)];
}
if ([textToMeasure.string hasSuffix:@"\n"])
{
[textToMeasure appendAttributedString:[[NSAttributedString alloc] initWithString:@"-" attributes:@{NSFontAttributeName: internalTextView.font}]];
}
// NSAttributedString class method: boundingRectWithSize:options:context is
// available only on ios7.0 sdk.
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return CGRectGetHeight(size) + fudgeFactor.height;
}
else
{
return self.internalTextView.contentSize.height;
}
}
IOS 7以降を使用している場合は、自動レイアウトをオンにして、テキストビューの各辺をその親ビューのエッジに固定するだけで正常に機能します。追加のコードは必要ありません。
ストーリーボードで制約を使用する場合、UITextViewのxcodeの右側のペインの「ルーラー」タブでスーパービューに制約されていることを確認してください。私の問題は、「Trailing space to」に-80ポイントの制約があることでした。
Bilobatumの答えは、自動レイアウト、つまりテキストビューのサブクラス化で完全に機能しました。
テキストビューの高さを制限する場合は、別の制約を追加します(ストーリーボード、つまり高さ<= 166(必要に応じて高さ)を使用して追加しました)
次に、サブクラス内で、高さ制約の優先度を750(self.heightConstraint.priority = 750)に下げて、サブクラスに追加された高さ制約とストーリーボードに追加された高さ制約の間の競合を回避します。
IOS 8では、親からコンテンツオフセットを継承しますが、これも同様に取り除く必要があります。
サブクラスの例
// Originally from https://github.com/Nikita2k/resizableTextView
#import "ResizableTextView.h"
@implementation ResizableTextView
- (void) updateConstraints {
// calculate contentSize manually
// ios7 doesn't calculate it before viewDidAppear and we'll get here before
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];
// set the height constraint to change textView height
[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = contentSize.height;
*stop = YES;
}
}];
[super updateConstraints];
}
- (void)setContentOffset:(CGPoint)contentOffset
{
// In iOS 8 we seem to be inheriting the content offset from the parent.
// I'm not interested
}
@end
UITextView
にカテゴリを書きました:
- (CGSize)intrinsicContentSize {
return self.contentSize;
}
- (void)setContentSize:(CGSize)contentSize {
[super setContentSize:contentSize];
[self invalidateIntrinsicContentSize];
}
UIKit
がcontentSize
を設定すると、UITextView
はintrinsic content size
を調整します。 autolayout
でうまく動作します。
自動レイアウトを使用しているユーザーがsizetofitが機能しない場合は、幅の制約を一度確認してください。幅の制約を逃した場合、高さは正確になります。
他のAPIを使用する必要はありません。 1行だけですべての問題が修正されます。
[_textView sizeToFit];
ここでは、幅を固定したまま、高さのみに関心があり、ストーリーボードのTextViewの幅の制約を逃していました。
そして、これはサービスからの動的コンテンツを表示することでした。
これが役立つことを願っています。