iOS:テキストの長さに応じてUIButtonのサイズを変更


134

インターフェースビルダーでは、Command+ =を押すとボタンのサイズがテキストに合わせて変更されます。ボタンがビューに追加される前に、これをプログラムで実行できるかどうか疑問に思っていました。

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12]];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
// I need to know the width needed to accomodate NSStringVariable
[button setTitle:NSStringVariable forState:UIControlStateNormal]; 
// So that I can set the width property of the button before addSubview
[button setFrame:CGRectMake(10, 0, width, fixedHeight)];
[subNavigation addSubview:button];

1
この非常に古い質問に注意してください:今日(2017)、制約を「以上」に設定するだけで、すべてが実行されます。(Tadによる以下の通知に注意してください。)
Fattie

@Fattie「以上」の制約ではオートレイアウトとの互換性を確保するには不十分です。今日では(2017+)1はどちらか(パルトロミエSemańczykの答え)適切にリサイズし、何かの内側にボタンをラップする必要があり、または1つは、のように、UIButtonのサブクラスを作成する必要がありstackoverflow.com/a/50575588/1033581
・クール

こんにちは@Cœur-自動レイアウトには多くの微妙な点があります。少し異なる状況を考えている可能性はありますか?しかし、幸いにも、あなたは完全に間違っています- ちょうどそれを試してください !! ビューコントローラーにUIButtonを置くだけです。明らかに水平と垂直の中心を設定します。次に、100以上の幅制約を追加します。最新のiOSで完全に動作します。
Fattie

1
(ここで自動レイアウトグーグルを初めて使用する人は、TBCだけを追加する必要はありません。UIButton(UILabelなど)も、テキストの変更に応じて自動的に幅にサイズ変更されます。 H / V位置を適切に拘束します。)
Fattie、

@Fattieのデモンストレーション。:具体的には、実行時に、それはそのように振る舞うgithub.com/Coeur/autolayoutButton/blob/master/buttonSelfSizing/...
・クール

回答:


1

Xcode 4.5以降では、これは ' Auto-layouting / Constraints ' を使用して実行できるようになりました。

主な利点は次のとおりです。

  1. プログラムでフレームを設定する必要はまったくありません!
  2. 正しく行われていれば、向きを変更するためにフレームをリセットする必要はありません。
  3. また、デバイスの変更に煩わされる必要はありません(読み取り、画面サイズごとに個別にコーディングする必要はありません)。

いくつかの欠点:

  1. 下位互換性はありません-iOS 6以降でのみ機能します。
  2. 慣れる必要があります(ただし、後で時間を節約できます)。

最もクールなことは、次のようなインテントの宣言に集中できることです。

  • これら2つのボタンの幅を同じにしたいのですが。または
  • このビューを垂直方向の中央に配置し、スーパービューの端から最大10ポイントの範囲に拡張する必要があります。あるいは、
  • このボタン/ラベルを、表示しているラベルに合わせてサイズ変更したい!

これは、自動レイアウトを紹介する簡単なチュートリアルです。

詳細について

最初は少し時間がかかりますが、努力する価値があるように思えます。


3
私はこの回答を見逃しそうでした-それは本当にもっと多くの賛成票が必要です。このソリューションを使用すると、フォントのフェース名とサイズ、またはiOS 7のみの呼び出しの埋め込みを回避できます。UIButtonを拡張したい側の制約を設定するだけです。
Carl

/:あなたはtitleEdgeInsets使用する場合、ほとんど完璧なソリューションでは、残念ながらそれは動作しません
ゾルタン・

130
これは不適切な答えです。この状況でAutoLayoutを適用して質問者の問題を解決する方法ではなく、AutoLayout自体のメリットを詳しく説明しています。
mattsven 2015

4
これをプログラムで行うことが可能かどうか疑問に思っていましたが、答えは...
フアンボエロ2015

@JuanPabloBoeroAlvarez自動レイアウト制約は、Interface Builderで、またはプログラムで指定できます。
Slipp D. Thompson 2016

130

UIKitでは、特定のフォントでレンダリングされたときに必要なサイズを、指定されたNSStringオブジェクトから取得するためのNSStringクラスへの追加があります。

ドキュメントはここにありました。今ではだ、ここで非推奨の下で。

要するに、あなたが行くなら:

CGSize stringsize = [myString sizeWithFont:[UIFont systemFontOfSize:14]]; 
//or whatever font you're using
[button setFrame:CGRectMake(10,0,stringsize.width, stringsize.height)];

...ボタンのフレームを、レンダリングする文字列の高さと幅に設定します。

おそらく、そのCGSizeの周りにいくつかのバッファースペースを試してみたいと思いますが、適切な場所から始めます。


4
iOSのデフォルトのパディングは12px、8pxのようです。
ベンラックマン、2012

19
sizeWithFontはiOS 7.0では非推奨です。代わりにsizeWithAttributes:を使用してください
carmen_munich 2013年

6
フレームをいじるのではなく、コンストレイントのみを使うことを強くお勧めします。
Gil Sand

@GilSandこれにインターフェースビルダーを使用する方法はありますか?
ハギー2017

はい、グーグル検索はあなたに多くの有益な結果を与えるはずです
ギルサンド

101

コードでこれを行う方法は次のとおりです。

[button sizeToFit];

サブクラスを作成していて、ルールを追加したい場合は、オーバーライドできます。

- (CGSize)sizeThatFits:(CGSize)size;

5
sizeToFitは、UIButtonやUILabelなどの標準コントロールで完全に機能します。カスタムUIViewで実行する場合は、実装する必要があります-(CGSize)sizeThatFits:(CGSize)size
Cameron Lowell Palmer、

4
これは、テキストを設定した後に配置した場合にのみ機能します。それ以外の場合は、その大きさに関する十分な情報がありません。 [button setTitle:@"Your text here" forState:UIControlStateNormal]; [button sizeToFit]; また、後でテキストを更新する場合は、もう一度呼び出すことを忘れないでください。
ファンボエロ2015

その方法でのみテキストを設定するようにしてください:[myButton setTitle:@ "my title" forState:UIControlStateNormal]; 私にとっては、その発言を繰り返すまでうまくいきませんでした。
Darius Miliauskas 16年

7
sizeToFit()タイトルエッジのインセットは考慮されません。
ケリン

32

ボタンがInterface Builderで作成され、コードのタイトルを変更する場合は、次のようにできます。

[self.button setTitle:@"Button Title" forState:UIControlStateNormal];
[self.button sizeToFit];

1
そして、あなたのボタンがコードで作られたとしても、あなたはそれをすることができます。
マーカス

22

迅速:

ここで重要なのはいつを呼び出すのかということです.sizeToFit()。これは、表示するテキストを設定した後で、必要なサイズを読み取れるようにする必要があります。後でテキストを更新する場合は、もう一度呼び出します。

var button = UIButton()
button.setTitle("Length of this text determines size", forState: UIControlState.Normal)
button.sizeToFit()
self.view.addSubview(button)

18

自動レイアウトを使用してこれを実現するには、可変幅制約を設定してみてください。

幅の制約

また、調整してContent Hugging PriorityContent Compression Resistance Priority必要な結果を得る必要がある場合もあります。


UILabelは完全に自動的にサイズを自動調整します

このUILabelは単に画面の中央に配置されるように設定されています(2つの制約のみ、水平/垂直)。

それは完全に自動的に幅を変更します:

幅や高さを設定する必要はありません-それは完全に自動です。

ここに画像の説明を入力してください

ここに画像の説明を入力してください

小さな黄色の四角が単純に接続されていることに注意してください(ゼロの「間隔」)。UILabelのサイズが変更されると、自動的に移動します。

"> ="制約を追加すると、UILabelの最小幅が設定されます。

ここに画像の説明を入力してください


16

ボタンではなくテキストのサイズを変更したい場合は、...

button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = .5;
// The .5 value means that I will let it go down to half the original font size 
// before the texts gets truncated

// note, if using anything pre ios6, you would use I think
button.titleLabel.minimumFontSize = 8;

3
* adjustsFontSizeToFitWidth
Daniel Bang

8

sizeToFitが正しく機能しません。代わりに:

myButton.size = myButton.sizeThatFits(CGSize.zero)

contentInsetボタンに追加することもできます:

myButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 4, 8)


sizeToFitに関するAppleのドキュメントから://現在のビューの境界でsizeThatFits:を呼び出し、境界のサイズを変更します。したがって、正しく機能するので、後でテキストを設定するだけです。
マーカス

5

単に:

  1. UIView周りのビューに自動レイアウトでラッパーとして作成します。
  2. UILabelそのラッパーの中に入れます。ラッパーの端にラベルを貼り付ける制約を追加します。
  3. UIButtonラッパーの中に入れてから、と同じ制約を追加しますUILabel
  4. テキストとともに自動サイズのボタンをお楽しみください。

1
これはアクセシビリティとうまく機能しますか?
jasonszhao 2018

4

Swift 4.2

神に感謝、これは解決しました。ボタンにテキストを設定した後、UIViewから自然なサイズである組み込みコンテンツサイズを取得できます(公式ドキュメントはこちらです)。UIButtonの場合、以下のように使用できます。

button.intrinsicContentSize.width

参考までに、幅が適切に見えるように調整しました。

button.frame = CGRect(fx: xOffset, y: 0.0, width: button.intrinsicContentSize.width + 18, height: 40)

シミュレーター

builtContentSizeを持つUIButton

出典:https : //riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-based-on-its-text-and-font


1
もう少しコンテキストを教えてもらえますか?あなたのコード行は問題のコードとどのように関連していますか?あなたが提案するコードが何をするかについても要約できますか?説明としてリンクを提供するだけでは、このサイトに適切な形式ではありません(理由についてはmeta.stackexchange.com/a/8259/266197を参照してください)。ただし、説明とコンテキストを追加すると、回答の価値が高まります。
NOH、

3

この投稿に関連して、sizeToFit解決できない追加のニーズがいくつかあります。テキストに関係なく、ボタンを元の場所の中央に配置する必要がありました。また、ボタンを元のサイズより大きくしたくありません。

そこで、ボタンを最大サイズにレイアウトし、そのサイズをコントローラーに保存し、次のメソッドを使用して、テキストが変更されたときにボタンのサイズを変更します。

+ (void) sizeButtonToText:(UIButton *)button availableSize:(CGSize)availableSize padding:(UIEdgeInsets)padding {    

     CGRect boundsForText = button.frame;

    // Measures string
    CGSize stringSize = [button.titleLabel.text sizeWithFont:button.titleLabel.font];
    stringSize.width = MIN(stringSize.width + padding.left + padding.right, availableSize.width);

    // Center's location of button
    boundsForText.origin.x += (boundsForText.size.width - stringSize.width) / 2;
    boundsForText.size.width = stringSize.width;
    [button setFrame:boundsForText];
 }

1

テキストの高さを自動サイズ変更するこのボタンクラス(Xamarin用ですが、他の言語に書き換えることができます)

[Register(nameof(ResizableButton))]
public class ResizableButton : UIButton
{
    NSLayoutConstraint _heightConstraint;
    public bool NeedsUpdateHeightConstraint { get; private set; } = true;

    public ResizableButton(){}

    public ResizableButton(UIButtonType type) : base(type){}

    public ResizableButton(NSCoder coder) : base(coder){}

    public ResizableButton(CGRect frame) : base(frame){}

    protected ResizableButton(NSObjectFlag t) : base(t){}

    protected internal ResizableButton(IntPtr handle) : base(handle){}

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        UpdateHeightConstraint();
        InvalidateIntrinsicContentSize();
    }

    public override void SetTitle(string title, UIControlState forState)
    {
        NeedsUpdateHeightConstraint = true;
        base.SetTitle(title, forState);
    }

    private void UpdateHeightConstraint()
    {
        if (!NeedsUpdateHeightConstraint)
            return;
        NeedsUpdateHeightConstraint = false;
        var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));

        var rect = new CGRect(Frame.X, Frame.Y, Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);

        if (_heightConstraint != null)
            RemoveConstraint(_heightConstraint);

        _heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, rect.Height);
        AddConstraint(_heightConstraint);
    }

     public override CGSize IntrinsicContentSize
     {
         get
         {
             var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));
             return new CGSize(Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);
         }
     }
}

1

どういうわけかfunc sizeToFit()、私のために動作しません。私の設定では、内部のボタンを使用しており、UITableViewCell自動レイアウトを使用しています。

私のために働いたのは:

  1. 幅の制約を取得する
  2. intrinsicContentSizeこのドキュメントによれば、自動レイアウトはを認識しないため、幅を取得しintrinsicContentSizeます。幅の制約を設定するintrinsicContentSize

ここに画像の説明を入力してください

ここから2つのタイトルがあります Debug View Hierachry ここに画像の説明を入力してください

ここに画像の説明を入力してください


0

正直言って、ストーリーボードにテキストに合わせてボタンのサイズを変更したいという単純なチェックボックスがないのは本当に残念だと思います。まあ...何でも。

これは、ストーリーボードを使用する最も簡単なソリューションです。

  1. UIViewを配置して制約を設定します。例: ここに画像の説明を入力してください
  2. UILabelをUIView内に配置します。UIViewのエッジにアタッチするように制約を設定します。

  3. UIView内にUIButtonを配置します。同じ制約を設定して、UIViewのエッジにアタッチします。

  4. UILabelの行数を0に設定します。 ここに画像の説明を入力してください

  5. コンセントを設定します。

    @IBOutlet var button: UIButton!
    @IBOutlet var textOnTheButton: UILabel!
  1. 長い、長い、長いタイトルを取得します。

    let someTitle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
  1. viewDidLoadで、UILabelとUIButtonの両方のタイトルを設定します。

    override func viewDidLoad() {
        super.viewDidLoad()
        textOnTheButton.text = someTitle
        button.setTitle(someTitle, for: .normal)
        button.titleLabel?.numberOfLines = 0
    }
  1. それを実行して、ボタンのサイズが変更され、押すことができることを確認します。

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.