web-dev-qa-db-ja.com

幅ではなく高さのみを変更してUILabelをsizeToFitするにはどうすればよいですか?

[self.Review sizeToFit];

SizeToFitの前の結果:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {198, 63}}

SizeToFit後の結果:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {181, 45}}

幅は同じままにしておきたい。高さを変えたいだけです。自動マスクは

(lldb) po self.Review
(UILabel *) $1 = 0x08bb0fe0 <UILabel: 0x8bb0fe0; frame = (90 20; 181 45); text = 'I'm at Mal Taman Anggrek ...'; clipsToBounds = YES; opaque = NO; autoresize = LM+RM+H; userInteractionEnabled = NO; layer = <CALayer: 0x8bb68b0>>

私はそれを行う方法があることを知っています: テキストサイズに合わせてUILabelの幅を調整して作成する方法?

答えは奇妙です(フォント情報を再提供する必要があります)。または不明。

また、最大幅を定義し、sizeToFitがその最大幅より大きい幅を与えた場合の対処方法をプログラムに指示する必要があります。

sizeWithFontを使用するという奇妙なソリューションを使用します。 UILabelはラベルのフォントを既に知っているため、奇妙です。

実際、sizeToFitはどのように動作しますか? UILabelをより薄くするか、より高くする必要があるかどうかは、どのように決定しますか?

34
Anonymous White

これがどのように行われるかです。ラベルにはすでにフォント情報が含まれているため、このメソッド呼び出しにラベルを含めるのは簡単です。

CGSize size = [label.text sizeWithFont:label.font
                     constrainedToSize:CGSizeMake(maxWidth, MAXFLOAT)
                         lineBreakMode:UILineBreakModeWordWrap]; 
CGRect labelFrame = label.frame;
labelFrame.size.height = size.height;
label.frame = labelFrame;

最新のboundingRectWithSizeを使用したSwiftバージョン:

let maxHeight = CGFloat.infinity
let rect = label.attributedText?.boundingRectWithSize(CGSizeMake(maxWidth, maxHeight), 
       options: .UsesLineFragmentOrigin, context: nil)
var frame = label.frame
frame.size.height = rect.size.height
label.frame = frame
41
Mundi

SizeThatFitsでも同じ結果を得ることができます。

CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
CGRect frame = label.frame;
frame.size.height = size.height;
label.frame = frame;

または、sizeToFitを使用します。

CGRect frame = label.frame;
[label sizeToFit];
frame.size.height = label.frame.size.height;
label.frame = frame;
40
vadimtrifonov

sizeToFitは素晴らしい作品です。唯一の問題は、コントロールの現在のサイズに基づいていることです。

たとえば、ラベル付きのテーブルビューセルをリサイクルする場合、ラベルの幅が前のセルで縮小されている可能性があるため、sizeToFitの呼び出しは信頼できないように見える場合があります。

SizeToFitメッセージを送信する前に、コントロールの元の幅をリセットするだけです。

17
chrilith

2017年の回答...

c = CGSize(width:yourWidth、height:CGFloat.greatestFiniteMagnitude)
result = sizeThatFits(c).height

そう...

let t = .... your UITextView
let w = .... your known width of the item

let trueHeight = t.sizeThatFits(
                   CGSize(width: t, height: CGFloat.greatestFiniteMagnitude)).height

それでおしまい。


非常に多くの場合、「通常の」1行エントリと比較した高さのdifferenceを知りたい

これは、特にUTableViewとは関係のないある種のセル(たとえば、ある種のカスタムスタックビュー)を作成している場合に発生します。ある時点で高さを手動で設定する必要があります。ストーリーボードで、通常の状況ではもちろん1行だけの短い文字列(たとえば「A」)のサンプルテキストを使用して、希望どおりにビルドします。次に、このようなことをします...

func setTextWithSizeCorrection() { // an affaire iOS

    let t = .... your UITextView
    let w = .... your known width of the item

    let oneLineExample = "A"
    let actualText = yourDataSource[row].description.whatever

    // get the height as if with only one line...

    experimental.text = oneLineExample
    let oneLineHeight = t.sizeThatFits(
               CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height

    // get the height with the actual long text...
    // (note that usually, you do not want a one-line minimum)

    experimental.text = (actualText == "") ? oneLineExample : actualText
    let neededHeight = t.sizeThatFits(
              CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height

    experimental.text = actualText

    let delta = neededHeight - oneLineHeight

    set the height of your cell, or whatever it is(standardHeight + delta)
}

最後のポイント:iOSで本当に愚かなことの1つは、UITextViewの内部に奇妙な種類のマージンがあることです。これは、UITextViewとラベルを単に入れ替えることができないことを意味します。そして、それは他の多くの問題を引き起こします。 Apple執筆時点でこの問題は修正されていません。問題を修正するのは困難です。通常、次のアプローチで問題ありません。

@IBDesignable class UITextViewFixed: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    func setup() {
        textContainerInset = UIEdgeInsets.zero;
        textContainer.lineFragmentPadding = 0;
    }
}

壊れた、使用できないAppleのUITextView ...

enter image description here

UITextViewFixedは、ほとんどの場合、受け入れ可能な修正です。

enter image description here

(明確にするために黄色が追加されました。)

2
Fattie

NSStringsize...メソッド、UILabelはすでに@vatrifが指摘するように、そのためのAPIを既に持っています(内部的にはおそらくNSStringのメソッドのみを使用します)。

それでも、UILabelのAPIは改善されると思います。それが、カテゴリが最もエレガントなソリューションだと思う理由です。

//  UILabel+Resize.h
@interface UILabel (Resize)
- (void)sizeToFitHeight;
@end

//  UILabel+Resize.m
@implementation UILabel (Resize)
- (void)sizeToFitHeight {
    CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
    CGRect frame = self.frame;
    frame.size.height = size.height;
    self.frame = frame;
}
@end

一つだけ:私はそのメソッドの適切な名前がわからない:

  • sizeToFitHeight?
  • heightToFit?

コメントありがとうございます!

2
de.

合意されたAPIはこの追加の恩恵を受けます。作業を簡単にし、Swift=のUILabelクラスに拡張機能を追加します。

extension UILabel {

    func sizeToFitHeight() {
        let size:CGSize = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}
1
dijipiji

Swift 3。

extension UILabel {
    func sizeToFitHeight() {
        let size: CGSize = self.sizeThatFits(CGSize.init(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}
1
ndduong

Swiftの修正ソリューション

MaxHeightには_CGFloat.greatestFiniteMagnitude_を使用します。

_let size = CGSize.init(width: yourLabel.frame.size.width,
                       height: CGFloat.greatestFiniteMagnitude)
let rect = errorLabel.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
var frame = errorLabel.frame
frame.size.height = (rect?.size.height)!
errorLabel.frame = frame
_


またはUIlabel拡張機能を作成し、メソッドyourLabel. sizeToFitHeight()を呼び出します

_extension UILabel {

    func sizeToFitHeight() {
        let maxHeight : CGFloat = CGFloat.greatestFiniteMagnitude
        let size = CGSize.init(width: self.frame.size.width, height: maxHeight)
        let rect = self.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
        var frame = self.frame
        frame.size.height = (rect?.size.height)!
        self.frame = frame
    }

} 
_
1
MANISH PATHAK

Mundi の答えのSwift 3バージョン:

let maxHeight: CGFloat = 10000
let rect = label.attributedText!.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
                                                           options: .usesLineFragmentOrigin,
                                                           context: nil)
var frame = labe.frame
frame.size.height = rect.size.height
label.frame = frame
0
Artem Novichkov