UIButton:imageEdgeInsetsとtitleEdgeInsetsを使用して画像とテキストを中央に配置する方法?


159

ボタンに画像のみを配置し、imageEdgeInsetsを上部に近づけると、画像は中央にとどまり、すべて期待どおりに機能します。

[button setImage:image forState:UIControlStateNormal];
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, 0.0)];

ボタンにテキストのみを配置し、titleEdgeInsetsを下部に近づけると、テキストは中央に留まり、すべて期待どおりに機能します。

[button setTitle:title forState:UIControlStateNormal];
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, -30, 0.0)];

しかし、4行をまとめると、テキストが画像と干渉し、両方とも中央揃えが失われます。

すべての画像の幅は30ピクセルです。setTitleEdgeInsetsのUIEdgeInsetMakeの左側のパラメーターに30を設定すると、テキストが再び中央に配置されます。問題は、button.titleLabelのサイズに依存しているように見えるため、画像が中央に配置されないことです。私はすでにボタンサイズ、画像サイズ、titleLabelサイズで多くの計算を試みましたが、どちらも完全に中央に配置されることはありません。

誰かがすでに同じ問題を抱えていましたか?

回答:


412

価値があることについては、マジックナンバーを使用せずに画像をテキストの中央に配置する一般的な解決策を次に示します。次のコードは古くなっており、おそらく以下の更新されたバージョンの1つを使用する必要があることに注意してください

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered 
//  below the image
CGSize imageSize = button.imageView.frame.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
  0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = button.titleLabel.frame.size;
button.imageEdgeInsets = UIEdgeInsetsMake(
  - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

次のバージョンには、以下のコメントで推奨されているiOS 7以降をサポートするための変更が含まれています。私はこのコードを自分でテストしていないので、どのように機能するか、または以前のバージョンのiOSで使用した場合にコードが壊れるかどうかはわかりません。

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered 
//  below the image
CGSize imageSize = button.imageView.image.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
  0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
//  above the text
CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}];
button.imageEdgeInsets = UIEdgeInsetsMake(
  - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

// increase the content height to avoid clipping
CGFloat edgeOffset = fabsf(titleSize.height - imageSize.height) / 2.0;
button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0);

Swift 5.0バージョン

extension UIButton {
  func alignVertical(spacing: CGFloat = 6.0) {
    guard let imageSize = imageView?.image?.size,
      let text = titleLabel?.text,
      let font = titleLabel?.font
    else { return }

    titleEdgeInsets = UIEdgeInsets(
      top: 0.0,
      left: -imageSize.width,
      bottom: -(imageSize.height + spacing),
      right: 0.0
    )

    let titleSize = text.size(withAttributes: [.font: font])
    imageEdgeInsets = UIEdgeInsets(
      top: -(titleSize.height + spacing),
      left: 0.0,
      bottom: 0.0, right: -titleSize.width
    )

    let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0
    contentEdgeInsets = UIEdgeInsets(
      top: edgeOffset,
      left: 0.0,
      bottom: edgeOffset,
      right: 0.0
    )
  }
}

5
素晴らしい-ありがとう!私は他の多くの答えがこの「難しい方法」について行くと思います-これははるかに良く見えます。
Joe D'Andrea

3
上記は中華料理であることがわかりましたが、その方法についてのメンタルモデルはまったくありません。誰でも、個々のEdgeInsetsパラメータがどのような影響を与えるかについての画像による説明へのリンクを得ましたか?そして、なぜテキストの幅が変わったのでしょうか?
Robert Atkins、

3
画像がボタンに合わせて縮小されている場合、これは機能しません。UIButton(少なくともiOS 7では)がセンタリング計算にimageView.frame.sizeではなくimage.sizeを使用しているようです。
ダンジャクソン

5
@ヘマンとダンジャクソン、私はそれらを自分でテストせずにあなたの提案を取り入れています。私が最初にこれをiOS 4向けに書いたのはちょっとばかげていると思います。この多くのバージョンの後でも、このような明らかな機能を得るために、Appleのレイアウトアルゴリズムを本質的にリバースエンジニアリングする必要があります。または、少なくとも私は、賛成票の一貫した流れと以下の同様にハック的な回答からまだより良い解決策がないと思います(侮辱は意図されていません)。
Jesse Crossen、2014年

5
iOS8 button.currentTitleでは、button.titleLabel.text特にボタンのテキストが変更される場合は、代わりに使用する方が良いことがわかりました。currentTitleすぐに入力されtitleLabel.textますが、変更が遅くなり、インセットの位置がずれる可能性があります。
mjangda 2015

59

方法を見つけました。

最初に、テキストを構成しますtitleLabel(スタイル、つまり太字、斜体などのため)。次に、setTitleEdgeInsets画像の幅を考慮して使用します。

[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:10.0]];

// Left inset is the negative of image width.
[button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, -image.size.width, -25.0, 0.0)]; 

その後setTitleEdgeInsets、テキスト境界の幅を考慮して使用します。

[button setImage:image forState:UIControlStateNormal];

// Right inset is the negative of text bounds width.
[button setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, -button.titleLabel.bounds.size.width)];

これで画像とテキストが中央に配置されます(この例では、画像はテキストの上に表示されます)。

乾杯。


3
7年、男。本当に覚えていない。私が尋ねたとき、私は自分自身に答えました(当時は私の答えが唯一の答えでした)。現在選択されている回答の作成者がそれらのマジックナンバーの削除に重点を置いたときに、選択された回答を変更しました。したがって、選択した回答で、それらの意味を理解できます。
reinaldoluckman

20

これは、Jesse Crossenの回答に部分的に基づいたこのSwift拡張機能で実行できます。

extension UIButton {
  func centerLabelVerticallyWithPadding(spacing:CGFloat) {
    // update positioning of image and title
    let imageSize = self.imageView.frame.size
    self.titleEdgeInsets = UIEdgeInsets(top:0,
                                        left:-imageSize.width,
                                        bottom:-(imageSize.height + spacing),
                                        right:0)
    let titleSize = self.titleLabel.frame.size
    self.imageEdgeInsets = UIEdgeInsets(top:-(titleSize.height + spacing),
                                        left:0,
                                        bottom: 0,
                                        right:-titleSize.width)

    // reset contentInset, so intrinsicContentSize() is still accurate
    let trueContentSize = CGRectUnion(self.titleLabel.frame, self.imageView.frame).size
    let oldContentSize = self.intrinsicContentSize()
    let heightDelta = trueContentSize.height - oldContentSize.height
    let widthDelta = trueContentSize.width - oldContentSize.width
    self.contentEdgeInsets = UIEdgeInsets(top:heightDelta/2.0,
                                          left:widthDelta/2.0,
                                          bottom:heightDelta/2.0,
                                          right:widthDelta/2.0)
  }
}

これはcenterLabelVerticallyWithPadding、タイトルと画像インセットを適切に設定する関数を定義します。

また、contentEdgeInsetsも設定します。これintrinsicContentSizeは、Auto Layoutを使用する必要があるため、正しく動作することを確認するために必要だと思います。

UIKitコントロールをサブクラス化することは想定されていないため、UIButtonをサブクラス化するすべてのソリューションは技術的に不正です。つまり、理論的には将来のリリースで壊れる可能性があります。


iOS9でのテスト。画像は中央に表示されますが、テキストは左側に表示されます:(
endavid

13

編集:Swift 3用に更新

Jesse Crossenの答えのSwiftソリューションを探している場合は、UIButtonのサブクラスにこれを追加できます。

override func layoutSubviews() {

    let spacing: CGFloat = 6.0

    // lower the text and push it left so it appears centered
    //  below the image
    var titleEdgeInsets = UIEdgeInsets.zero
    if let image = self.imageView?.image {
        titleEdgeInsets.left = -image.size.width
        titleEdgeInsets.bottom = -(image.size.height + spacing)
    }
    self.titleEdgeInsets = titleEdgeInsets

    // raise the image and push it right so it appears centered
    //  above the text
    var imageEdgeInsets = UIEdgeInsets.zero
    if let text = self.titleLabel?.text, let font = self.titleLabel?.font {
        let attributes = [NSFontAttributeName: font]
        let titleSize = text.size(attributes: attributes)
        imageEdgeInsets.top = -(titleSize.height + spacing)
        imageEdgeInsets.right = -titleSize.width
    }
    self.imageEdgeInsets = imageEdgeInsets

    super.layoutSubviews()
}

9

ここにはいくつかの素晴らしい例がありますが、複数行のテキスト(テキストの折り返し)を処理するときに、これをすべてのケースで機能させることはできませんでした。最後にそれを動作させるために、私はいくつかのテクニックを組み合わせました:

  1. 上記のJesse Crossenの例を使用しました。ただし、テキストの高さの問題を修正し、水平方向のテキストマージンを指定する機能を追加しました。マージンは、テキストを折り返してボタンの端に当たらないようにする場合に役立ちます。

    // the space between the image and text
    CGFloat spacing = 10.0;
    float   textMargin = 6;
    
    // get the size of the elements here for readability
    CGSize  imageSize   = picImage.size;
    CGSize  titleSize   = button.titleLabel.frame.size;
    CGFloat totalHeight = (imageSize.height + titleSize.height + spacing);      // get the height they will take up as a unit
    
    // lower the text and push it left to center it
    button.titleEdgeInsets = UIEdgeInsetsMake( 0.0, -imageSize.width +textMargin, - (totalHeight - titleSize.height), +textMargin );   // top, left, bottom, right
    
    // the text width might have changed (in case it was shortened before due to 
    // lack of space and isn't anymore now), so we get the frame size again
    titleSize = button.titleLabel.bounds.size;
    
    button.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + spacing), 0.0, 0.0, -titleSize.width );     // top, left, bottom, right        
    
  2. 折り返すようにテキストラベルを設定してください

    button.titleLabel.numberOfLines = 2; 
    button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
    button.titleLabel.textAlignment = UITextAlignmentCenter;
    
  3. これはほとんど今動作します。ただし、画像が正しく表示されないボタンがいくつかありました。画像が右または左にずれる(中央に配置されなかった)。そのため、UIButtonレイアウトオーバーライド手法を使用して、imageViewを中央に配置しました。

    @interface CategoryButton : UIButton
    @end
    
    @implementation CategoryButton
    
    - (void)layoutSubviews
    {
        // Allow default layout, then center imageView
        [super layoutSubviews];
    
        UIImageView *imageView = [self imageView];
        CGRect imageFrame = imageView.frame;
        imageFrame.origin.x = (int)((self.frame.size.width - imageFrame.size.width)/ 2);
        imageView.frame = imageFrame;
    }
    @end
    

これは良い解決策のようですが、button.titleLabel.numberOfLinesを0にして、必要な数の行にすることはできませんか?
ベンラックマン2013

私の場合、2行までしか望んでいませんでした。そうしないと、ボタンの全体的なサイズに関して画像に問題が発生します。
Tod Cunningham

9

@TodCunninghamの答えの方法を作りました

 -(void) AlignTextAndImageOfButton:(UIButton *)button
 {
   CGFloat spacing = 2; // the amount of spacing to appear between image and title
   button.imageView.backgroundColor=[UIColor clearColor];
   button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
   button.titleLabel.textAlignment = UITextAlignmentCenter;
   // get the size of the elements here for readability
   CGSize imageSize = button.imageView.frame.size;
   CGSize titleSize = button.titleLabel.frame.size;

  // lower the text and push it left to center it
  button.titleEdgeInsets = UIEdgeInsetsMake(0.0, - imageSize.width, - (imageSize.height   + spacing), 0.0);

  // the text width might have changed (in case it was shortened before due to 
  // lack of space and isn't anymore now), so we get the frame size again
   titleSize = button.titleLabel.frame.size;

  // raise the image and push it right to center it
  button.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, -     titleSize.width);
 }

7

Xcode 11以降向けに更新

私の元の回答で説明されているインセットは、より新しいバージョンのXcodeのサイズインスペクターに移動されました。切り替えがいつ発生したかは完全にはわかりませんが、属性インスペクタに挿入情報が見つからない場合は、サイズインスペクタを確認する必要があります。以下は、新しいインセット画面のサンプルです(11.5の時点でサイズ属性インスペクターの上部にあります)。

insets_moved_to_size_inspector

元の回答

他の答えには何の問題もありませんが、私は同じ動作がコードのゼロ行を使用してXcode内で視覚的に達成できることに注意したいだけです。このソリューションは、計算値が必要ない場合、またはストーリーボード/ xibを使用して構築している場合に役立ちます(そうでない場合、他のソリューションが適用されます)。

注-OPの質問がコードを必要とするものであることは理解しています。私は、完全性のために、そしてストーリーボード/ xibsを使用する人のための論理的な代替として、この答えを提供しています。

エッジインセットを使用してボタンの画像、タイトル、コンテンツビューの間隔を変更するには、ボタン/コントロールを選択して属性インスペクターを開きます。インスペクターの中央に向かって下にスクロールし、エッジインセットのセクションを見つけます。

エッジインセット

タイトル、画像、コンテンツビューの特定のエッジインセットにアクセスして変更することもできます。

メニューオプション


一部の値について、ストーリーボードに負の数値を入力できないように見えるのはなぜですか。
ダニエルT.

これは新しいSwiftバージョンで動作しますか?Edge属性がどこにも見つかりません
ブロックハンプトン

@brockhampton-新しい場所の最新の回答を参照
Tommie C.

6

システムと戦わないでください。レイアウトが複雑になり、Interface Builder +おそらくいくつかの単純な構成コードを使用して管理できない場合は、レイアウトを手動で使用して、より簡単な方法でレイアウトを実行しますlayoutSubviews。それが目的です!それ以外はすべてハッキングに相当します。

UIButtonサブクラスを作成し、そのlayoutSubviewsメソッドをオーバーライドして、テキストと画像をプログラムで調整します。または、https: //github.com/nickpaulson/BlockKit/blob/master/Source/UIView-BKAdditions.hなどを使用して、ブロックを使用してlayoutSubviewsを実装できます。


6

サブクラスUIButton

- (void)layoutSubviews {
    [super layoutSubviews];
    CGFloat spacing = 6.0;
    CGSize imageSize = self.imageView.image.size;
    CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(self.frame.size.width, self.frame.size.height - (imageSize.height + spacing))];
    self.imageView.frame = CGRectMake((self.frame.size.width - imageSize.width)/2, (self.frame.size.height - (imageSize.height+spacing+titleSize.height))/2, imageSize.width, imageSize.height);
    self.titleLabel.frame = CGRectMake((self.frame.size.width - titleSize.width)/2, CGRectGetMaxY(self.imageView.frame)+spacing, titleSize.width, titleSize.height);
}

6

Swift 4向けのJesse Crossenの回答の更新:

extension UIButton {
    func alignVertical(spacing: CGFloat = 6.0) {
        guard let imageSize = self.imageView?.image?.size,
            let text = self.titleLabel?.text,
            let font = self.titleLabel?.font
            else { return }
        self.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0.0)
        let labelString = NSString(string: text)
        let titleSize = labelString.size(withAttributes: [kCTFontAttributeName as NSAttributedStringKey: font])
        self.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
        let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
        self.contentEdgeInsets = UIEdgeInsets(top: edgeOffset, left: 0.0, bottom: edgeOffset, right: 0.0)
    }
}

この方法を使用します。

override func viewDidLayoutSubviews() {
    button.alignVertical()
}

何時間も経ってから。これが機能した唯一の方法でした:)
Harry Blue

4

このコードのチャンクを使用すると、次のようなものが得られます タイトルと画像の配置

extension UIButton {
    func alignTextUnderImage() {
        guard let imageView = imageView else {
                return
        }
        self.contentVerticalAlignment = .Top
        self.contentHorizontalAlignment = .Center
        let imageLeftOffset = (CGRectGetWidth(self.bounds) - CGRectGetWidth(imageView.bounds)) / 2//put image in center
        let titleTopOffset = CGRectGetHeight(imageView.bounds) + 5
        self.imageEdgeInsets = UIEdgeInsetsMake(0, imageLeftOffset, 0, 0)
        self.titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset, -CGRectGetWidth(imageView.bounds), 0, 0)
    }
}

2
ボタン内に画像とテキストを配置するための小さな拡張機能を書きました。興味があれば、ここにソースコードがあります。github.com/sssbohdan/ButtonAlignmentExtension/blob/master/...
ボフダンSavych

4

Swift 3+構文のUIButton拡張:

extension UIButton {
    func alignImageAndTitleVertically(padding: CGFloat = 6.0) {
        let imageSize: CGSize = imageView!.image!.size
        titleEdgeInsets = UIEdgeInsetsMake(0.0, -imageSize.width, -(imageSize.height + padding), 0.0)
        let labelString = NSString(string: titleLabel!.text!)
        let titleSize = labelString.size(attributes: [NSFontAttributeName: titleLabel!.font])
        self.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + padding), 0.0, 0.0, -titleSize.width)
        let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0;
        self.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0)
    }
}

元の答え:https : //stackoverflow.com/a/7199529/3659227


3

Jesse Crossenの答えを少し変更しただけで、完全に機能しました。

の代わりに:

CGSize titleSize = button.titleLabel.frame.size;

私はこれを使用しました:

CGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName:button.titleLabel.font}];

SOへようこそ!(マイナーな変更のために)個別の回答を追加する代わりに、これをJesseに直接書き込んで、彼が(受け入れられた)回答を(必要に応じて)正しく確認および更新できるようにすることができます。
Hemang 2014年

3

button.titleLabel.frame.size.widthラベルが切り捨てられないように十分に短い場合にのみ、を使用できます。ただし、ラベルテキストが切り捨てられた場合、配置は機能しません。取る

CGSize titleSize = [[[button titleLabel] text] sizeWithFont:[[button titleLabel] font]];

ラベルテキストが切り捨てられている場合でも、私にとっては機能します。


あなたはボタンのタイプミスを持っています。
Bhimbim、2016年

2

既存の回答を確認しましたが、ボタンフレームの設定が重要な最初のステップであることもわかりました。

これを処理する私が使用する関数は次のとおりです。

const CGFloat kImageTopOffset   = -15;
const CGFloat kTextBottomOffset = -25;

+ (void) centerButtonImageTopAndTextBottom: (UIButton*)         button 
                                     frame: (CGRect)            buttonFrame
                                      text: (NSString*)         textString
                                 textColor: (UIColor*)          textColor
                                      font: (UIFont*)           textFont
                                     image: (UIImage*)          image
                                  forState: (UIControlState)    buttonState
{
    button.frame = buttonFrame;

    [button setTitleColor: (UIColor*)       textColor
                 forState: (UIControlState) buttonState];

    [button setTitle: (NSString*) textString
            forState: (UIControlState) buttonState ];


    [button.titleLabel setFont: (UIFont*) textFont ];

    [button setTitleEdgeInsets: UIEdgeInsetsMake( 0.0, -image.size.width, kTextBottomOffset,  0.0)]; 

    [button setImage: (UIImage*)       image 
            forState: (UIControlState) buttonState ];

    [button setImageEdgeInsets: UIEdgeInsetsMake( kImageTopOffset, 0.0, 0.0,- button.titleLabel.bounds.size.width)];
}

2

または、このカテゴリを使用することもできます。

@interface UIButton (VerticalLayout)  

- (void)centerVerticallyWithPadding:(float)padding;  
- (void)centerVertically;  

@end  


@implementation UIButton (VerticalLayout)  

- (void)centerVerticallyWithPadding:(float)padding 
{      
    CGSize imageSize = self.imageView.frame.size;  
    CGSize titleSize = self.titleLabel.frame.size;  

    CGFloat totalHeight = (imageSize.height + titleSize.height + padding);  

    self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height),
                                            0.0f,
                                            0.0f,
                                            - titleSize.width);

    self.titleEdgeInsets = UIEdgeInsetsMake(0.0f,
                                            - imageSize.width,
                                            - (totalHeight - titleSize.height),
                                            0.0f);

}


- (void)centerVertically
{  
    const CGFloat kDefaultPadding = 6.0f;

    [self centerVerticallyWithPadding:kDefaultPadding];  
}  


@end

1
これはカスタムフォントでは機能しません。iOS7以降CGSize titleSize = [button.titleLabel.text sizeWithAttributes: @{NSFontAttributeName: button.titleLabel.font}];
Hemang

1

私の使用例では、インセットを管理できなくなりました。

  1. ボタンの背景画像の一貫性を維持
  2. 文字列の長さと画像のサイズが異なる動的テキストと画像の変更

これは私がやったことであり、私はそれでかなり満足しています:

  • 背景画像(ぼかしと色の付いた丸い円)を使用して、ストーリーボードにボタンを作成します。

  • クラスでUIImageViewを宣言します。

    @implementation BlahViewController {
        UIImageView *_imageView;
    }
  • initにイメージビューのインスタンスを作成します。

    -(id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            _imageView = [[UIImageView alloc] initWithCoder:aDecoder];
         }
         return self;
     }
  • viewDidLoadで、画像ビューのボタンに新しいレイヤーを追加し、テキストの配置を設定します。

    [self.btn addSubview:_imageView];
    [self.btn.titleLabel setTextAlignment:NSTextAlignmentCenter];
  • ボタンクリックメソッドで、選択したオーバーレイ画像を画像ビューに追加し、画像に合わせてサイズを調整し、ボタンの中央に配置しますが、15だけ上に移動して、テキストオフセットをその下に配置できます。

    [_imageView setImage:[UIImage imageNamed:@"blahImageBlah]];
    [_imageView sizeToFit];
    _imageView.center = CGPointMake(ceilf(self.btn.bounds.size.width / 2.0f),
             ceilf((self.btn.bounds.size.height / 2.0f) - 15));
    [self.btn setTitle:@"Some new text" forState:UIControlStateNormal];

注:ceilf()は、イメージの品質のためにピクセル境界上にあることを確認するために重要です。


1
ボタンをスタックビューに追加しているので、私のユースケースにも間違いなく優れたアプローチです。
valeCocoa 2017

0

テキストと画像の両方を水平方向に中央揃えにしたい場合は、テキストの上の画像:インターフェースビルダーからテキストを中央に配置し、上部のインセットを追加します(画像用のスペースを作ります)。(左インセットを0のままにします)。インターフェイスビルダーを使用して画像を選択します。実際の位置はコードから設定されるため、IBで問題が発生しないことを心配しないでください。上記の他の回答とは異なり、これは実際に現在サポートされているすべてのiOSバージョン(5、6、7)で機能します。

コードでは、画像を取得した後(ボタンの画像をnullに設定することにより)ボタンのImageViewを破棄します(これにより、テキストが自動的に中央に配置され、必要に応じて折り返されます)。次に、同じフレームサイズと画像で独自のImageViewをインスタンス化し、中央に配置します。

この方法でも、インターフェイスビルダーからイメージを選択できます(ただし、シミュレーターのようにIBで整列されることはありませんが、他のソリューションは、サポートされているすべてのiOSバージョン間で互換性がありません)。


0

ビューのコンストラクターで画像サイズとテキスト幅を取得できなかったため、これを実行するのに苦労していました。ジェシーの答えに対する 2つの小さな変更が私にとってうまくいきました:

CGFloat spacing = 3;
self.titleEdgeInsets = UIEdgeInsetsMake(0.0, - image.size.width, - (image.size.height + spacing), 0.0);
CGSize titleSize = [name sizeWithAttributes:@{NSFontAttributeName:self.titleLabel.font}];
self.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

変更点は次のとおりです。

  • [NSString sizeWithAttributes]テキストの幅を取得するために使用します。
  • UIImage代わりに直接画像サイズを取得するUIImageView

0

これは、画像の幅とタイトルの長さが異なる複数のボタンでうまく機能します。

サブクラス UIButton

override func layoutSubviews() {
    super.layoutSubviews()

    if let image = imageView?.image {

        let margin = 30 - image.size.width / 2
        let titleRect = titleRectForContentRect(bounds)
        let titleOffset = (bounds.width - titleRect.width - image.size.width - margin) / 2


        contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
            imageEdgeInsets = UIEdgeInsetsMake(0, margin, 0, 0)
            titleEdgeInsets = UIEdgeInsetsMake(0, (bounds.width - titleRect.width -  image.size.width - margin) / 2, 0, 0)
    }

}

0

ボタンサイズ80x80ピクセルで正常に動作します。

[self.leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, 10.0, 20.0, 10.0)];    
[self.leftButton setTitleEdgeInsets:UIEdgeInsetsMake(60, -75.0, 0.0, 0.0)];

0

画像を中央の水平に揃えるように調整しました。

// the space between the image and text
        let spacing = CGFloat(36.0);

        // lower the text and push it left so it appears centered
        //  below the image
        let imageSize = tutorialButton.imageView!.frame.size;
        tutorialButton.titleEdgeInsets = UIEdgeInsetsMake(
            0, -CGFloat(imageSize.width), -CGFloat(imageSize.height + spacing), 0.0);

        // raise the image and push it right so it appears centered
        //  above the text
        let titleSize = tutorialButton.titleLabel!.frame.size;
        tutorialButton.imageEdgeInsets = UIEdgeInsetsMake(
            -CGFloat(titleSize.height + spacing), CGFloat((tutorialButton.frame.width - imageSize.width) / 2), 0.0, -CGFloat(titleSize.width));

0

エッジインセットの使用は必須ですか?そうでない場合は、中央の親ビューを基準に配置してみてください

extension UIButton 
{
    func centerImageAndTextVerticaAlignment(spacing: CGFloat) 
    {
        var titlePoint : CGPoint = convertPoint(center, fromView:superview)
        var imageViewPoint : CGPoint = convertPoint(center, fromView:superview)
        titlePoint.y += ((titleLabel?.size.height)! + spacing)/2
        imageViewPoint.y -= ((imageView?.size.height)! + spacing)/2
        titleLabel?.center = titlePoint
        imageView?.center = imageViewPoint

    }
}

質問では、imageEdgeInsetsとtitleEdgeInsetsの使用を明示的に求めているため、必須である可能性が高い
Tibrogargan

0

画像をテキストの幅だけ右に移動する必要があります。次に、テキストを画像の幅だけ左に移動します。

UIEdgeInsets imageEdgeInsets = self.remoteCommandsButtonLights.imageEdgeInsets;
imageEdgeInsets.left = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:[button.titleLabel font]}].width;
imageEdgeInsets.bottom = 14.0;
button.imageEdgeInsets = imageEdgeInsets;

UIEdgeInsets titleEdgeInsets = self.remoteCommandsButtonLights.titleEdgeInsets;
titleEdgeInsets.left = -button.currentImage.size.width;
titleEdgeInsets.top = 20.0;
button.titleEdgeInsets = titleEdgeInsets;

次に、上下のインセットを調整してY軸を調整します。これはおそらくプログラムで行うこともできますが、画像サイズに対して一定である必要があります。一方、X軸のインセットは、各ボタンのテキストラベルのサイズに基づいて変更する必要があります。


0

このコードを拡張Swift 4.2に追加します。

 func moveImageLeftTextCenter(imagePadding: CGFloat = 30.0){
    guard let imageViewWidth = self.imageView?.frame.width else{return}
    guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
    self.contentHorizontalAlignment = .left
    imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imagePadding - imageViewWidth / 2, bottom: 0.0, right: 0.0)
    titleEdgeInsets = UIEdgeInsets(top: 0.0, left: (bounds.width - titleLabelWidth) / 2 - imageViewWidth, bottom: 0.0, right: 0.0)
}
func moveImageRIghtTextCenter(imagePadding: CGFloat = 30.0){
    guard let imageViewWidth = self.imageView?.frame.width else{return}
    guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
    self.contentHorizontalAlignment = .right
    imageEdgeInsets = UIEdgeInsets(top: 0.0, left:0.0 , bottom: 0.0, right: imagePadding - imageViewWidth / 2)
    titleEdgeInsets = UIEdgeInsets(top: 0.0, left:0.0 , bottom: 0.0, right:(bounds.width - titleLabelWidth) / 2 - imageViewWidth)
}

0

私の2セントを投入するだけで、これは私にとってうまくいきました:

extension UIButton {
  public func centerImageAndTextVertically(spacing: CGFloat) {
    layoutIfNeeded()
    let contentFrame = contentRect(forBounds: bounds)
    let imageFrame = imageRect(forContentRect: contentFrame)
    let imageLeftInset = bounds.size.width * 0.5 - imageFrame.size.width * 0.5
    let imageTopInset = -(imageFrame.size.height + spacing * 0.5)
    let titleFrame = titleRect(forContentRect: contentFrame)
    let titleLeftInset = ((bounds.size.width - titleFrame.size.width) * 0.5) - imageFrame.size.width
    let titleTopInmset = titleFrame.size.height + spacing * 0.5
    imageEdgeInsets = UIEdgeInsets(top: imageTopInset, left: imageLeftInset, bottom: 0, right: 0)
    titleEdgeInsets = UIEdgeInsets(top: titleTopInmset, left: titleLeftInset, bottom: 0, right: 0)
  }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.