iPhone UIButton-画像の位置


116

私が持っているUIButton「アプリを探検」とテキストでのUIImage(>)でInterface Builder、それは次のようになります。

[ (>) Explore the app ]

しかし、私UIImageはテキストの後にこれを配置する必要があります:

[ Explore the app (>) ]

UIImage右に移動するにはどうすればよいですか?


Interface Builderも使用できます。ここに私の答えをチェックアウト: stackoverflow.com/questions/2765024/...を
n8tr

1
数行のコードでこのサブクラスを使用するだけです:github.com/k06a/RTLButton
k06a

回答:


161

これに対する私の解決策は非常に簡単です

[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);

4
これはうまくいきます!エッジインセットのコンセプトを理解するのは難しいです。左端と右端の両方をインセットに設定する必要がある理由は何ですか?理論的には、タイトルを左に、画像を右に移動すれば十分です。なぜ左と右の両方を設定する必要があるのですか?
PokerIncome.com 2013


2
この答えは完璧に機能します。受け入れられた答えは正しく、正しいAPIドキュメントを指しますが、これはOPが要求したことを行うためのコピーアンドペーストソリューションです。
mclaughlinj 14年

ボタンのテキストを変更し始めると、少し複雑になります。この場合、サブクラス化されたソリューションの方がうまく機能しました。
ブラッドゴス2015年

左側と右側に同じ幅を適用する必要があることを示してくれてありがとう、私はそれがどのように機能するかを100%理解していません(サイズと原点に影響を与える場合があるため)が、同様の問題を解決できましたこの方法を使用します。
Toby

128

のiOS 9以降、これを達成する簡単な方法は、ビューのセマンティックを強制しているようです。

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

または、プログラムを使用して、以下を使用します。

button.semanticContentAttribute = .ForceRightToLeft

4
私があなたの答え(+1)を気に入っただけで、これを行うには「適切な」方法ではないかもしれませんが、それは最も簡単な方法の1つです。
farzadshbfn 2016年

@farzadshbfnあなたは正しいです。私はその言葉を「シンプル」に変更しました。より一貫しているようです。
Alvivi

@farzadshbfnなぜこれが「適切な」方法ではないのですか?
Samman Bikram Thapa

3
@SammanBikramThapa IMHO正しい方法は、UIButtonをサブクラス化semanticContentAttributeし、レイアウトロジックでsemanticContentAttributeそれ自体を変更するのではなく、レイアウトロジックでlayoutSubviewsと尊重をオーバーライドすることです。(セマンティックアプローチを変更すると、国際化ではうまく機能しません)
farzadshbfn

@farzadshbfnは完全に正しいです。この回答がほとんどのポイントを獲得したとしても、それは正しくありません-右から左へのインターフェイスのUXが壊れる可能性があります。
Pavel Yakimenko

86

imageEdgeInsetおよびtitleEdgeInsetを設定して、イメージ内でコンポーネントを移動します。フルサイズのグラフィックを使用してボタンを作成し、それをボタンの背景画像として使用することもできます(その後titleEdgeInsets、タイトルを移動するために使用します)。


8
サブクラスを実装するよりも、単にインセットを設定するほうがはるかに少ないコードです。これが差し込みの要点です。(作成していない)サブビューのフレームを操作することは、ハックのように感じられます。
キム・アンドレ・砂

6
@kimsnarf、本当に?画像のサイズやタイトルの長さを少し変更するだけで、インセットを微調整するほうがはるかに手間がかかりません(ハックも少なくなります)。
Kirk Woll 2013

54

レイモンドWの答えはここが一番です。カスタムlayoutSubviewsを持つサブクラスUIButton。実行するのが非常に簡単です、これは私のために働いたlayoutSubviews実装です:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

2
この方法は、多くのボタンを管理する必要がある場合に適していますが、変更する必要があるボタンは1つだけです:)
Pavel Yakimenko

2
ボタンの画像がnilの場合、おそらくUIImageViewが挿入されていないために、ラベルの位置が間違っています(iOS6.0でテスト済み)。imageView.imageがnilでない場合にのみ、フレームの編集を検討する必要があります。
Scakko 2013

2
両方のビューが中央に配置されるように、この回答に次の改善を提案します。CGFloat excessiveWidth = CGRectGetWidth(self.bounds)-累積幅; labelFrame.origin.x = excessWidth / 2; imageFrame.origin.x = CGRectGetMaxX(labelFrame)+ 10; '
i-konov 2014

これは私にとってiOS 7で壊れます。他に誰か?iOS 8で
正常に動作し

1
iOS7をまったくサポートしないでください。問題がなくなります。とにかくそれをサポートするべきではありません。
Gil Sand

30

サブクラス化UIButtonとオーバーライドについてはどうlayoutSubviewsですか?

次に、self.imageView&の位置を後処理しますself.titleLabel


4
これは、手動で調整したインセットを使用してすべてを正しく配置しようとすることに関する他のすべてのアドバイス(上記のものなど)よりもはるかに簡単です。
Steven Kramer

13

別の簡単な方法(iOS 9のみではない)は、UIButtonをサブクラス化してこれら2つのメソッドをオーバーライドすることです。

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}

contentEdgeInsets superを使用することで、すでに考慮されています。


ありがとう!私はこれをサブクラス化してlayoutSubviews()をオーバーライドする回答よりもずっと気に入っています:)
Joe Susnick

1
私の謙虚な意見でこれに
ついて行く最善の方法

9

アプリが「左から右」と「右から左」の両方をサポートしている場合、ボタンに「右から左」を強制するオプションはありません。

私のために働いたソリューションは、ストーリーボードのボタンに追加できるサブクラスであり、制約でうまく機能します(iOS 11でテスト済み):

class ButtonWithImageAtEnd: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let imageView = imageView, let titleLabel = titleLabel {
            let padding: CGFloat = 15
            imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding)
            titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width)
        }

    }

}

「パディング」は、タイトルと画像の間のスペースです。


もちろん.forceRightToLeftオプションです!場合は、反対の値(.forceLeftToRight)を使用しますUIApplication.shared.userInterfaceLayoutDirection == .rightToLeft
manmal

5

Swiftの場合:

override func layoutSubviews(){
    super.layoutSubviews()

    let inset: CGFloat = 5

    if var imageFrame = self.imageView?.frame,
       var labelFrame = self.titleLabel?.frame {

       let cumulativeWidth = imageFrame.width + labelFrame.width + inset
       let excessiveWidth = self.bounds.width - cumulativeWidth
       labelFrame.origin.x = excessiveWidth / 2
       imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

       self.imageView?.frame = imageFrame
       self.titleLabel?.frame = labelFrame  
    }
}

4

@splitによる回答の構築...

答えは素晴らしいですが、ボタンにカスタムイメージとタイトルエッジのインセットがあらかじめ設定されている(ストーリーボードなど)場合があるという事実は無視されます。

たとえば、コンテナの上部と下部から画像にパディングを付けたいが、画像をボタンの右側に移動したい場合があります。

私はこの方法でコンセプトを拡張しました:-

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

2
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

これにより、次のように右揃えのボタンが作成されます。

[           button label (>)]

ボタンはコンテキストに応じて幅を調整しないため、ラベルの左側にスペースが表示されます。これを解決するには、buttonLabelSize.widthとbuttonImageSize.widthからボタンのフレーム幅を計算します。



0

このソリューションはiOS 7以降で動作します

UIButtonをサブクラス化するだけ

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

使用法(クラスのどこか):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

0

以前の回答に基づいて構築します。アイコンとボタンのタイトルの間にマージンが必要な場合は、コードを少し変更して、本来のサイズのボタンの境界の上にラベルとアイコンが浮かないようにする必要があります。

let margin = CGFloat(4.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

最後のコード行は、自動レイアウトの本質的なコンテンツサイズの計算にとって重要です。


0

これが私のやり方です(約10年後)

  1. UIButtonのサブクラス(Swift時代に生きているButton)
  2. 画像とラベルをスタックビューに配置します。
class CustomButton: Button {

    var didLayout: Bool = false // The code must be called only once

    override func layoutSubviews() {
        super.layoutSubviews()
        if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
            didLayout = true
            let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
            addSubview(stack)
            stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
            stack.axis = .horizontal
        }
    }
}

0

Swiftの単一行ソリューション:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft

すべてのRTLユーザーのレイアウトを壊してしまうので、良くありません。彼らのために左から右に強制する必要があります。ここから他の解決策を試してみてください。
Pavel Yakimenko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.