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

3
최고의 해결책 I의 한을 FOUND
— Bimawa

2
이 답변은 완벽하게 작동합니다. 허용되는 대답은 정확하고 올바른 API 문서를 가리 키지 만 이것은 OP가 요청한 작업을 수행하는 복사 및 붙여 넣기 솔루션입니다.
— mclaughlinj 2014 년

버튼 텍스트를 변경하기 시작하면 약간 복잡해집니다. 이 경우 하위 클래스 솔루션이 더 잘 작동했습니다.
— Brad Goss 2015 년

왼쪽과 오른쪽에 동일한 너비를 적용해야한다는 것을 보여 주셔서 감사합니다. 어떻게 작동하는지 100 % 이해하지 못합니다 (때로는 원점뿐만 아니라 크기에도 영향을 미치기 때문입니다). 이 방법을 사용합니다.
— Toby

128

에 아이폰 OS 9 이후,이를 달성하는 간단한 방법은 뷰의 의미를 강제하는 것 같다.

여기에 이미지 설명 입력

또는 프로그래밍 방식으로 다음을 사용합니다.

button.semanticContentAttribute = .ForceRightToLeft

4
귀하의 답변 (+1)이 마음에 들었지만 "올바른"방법이 아닐 수도 있지만 가장 쉬운 방법 중 하나입니다.
— farzadshbfn 2016-06-25

@farzadshbfn 당신이 맞습니다. "단순"이라는 단어를 변경했는데 더 일관된 것 같습니다.
— Alvivi

@farzadshbfn 왜 이것이 "적절한"방법이 아닐까요?
— Samman Bikram Thapa

3
@SammanBikramThapa IMHO 적절한 방법은 UIButton을 하위 클래스로 만들고 semanticContentAttribute레이아웃 로직에서 layoutSubviews와 존중 을 재정의 하는 semanticContentAttribute것입니다. (의미 론적 접근 방식을 변경, 국제화 잘 작동하지 않습니다)
— farzadshbfn

@farzadshbfn이 완전히 옳습니다. 이 답변이 대부분의 점수를 얻더라도 정확하지 않습니다. 오른쪽에서 왼쪽으로의 인터페이스에 대한 UX가 손상 될 수 있습니다.
— Pavel Yakimenko 19.11.15

86

를 설정 imageEdgeInset하고 titleEdgeInset이미지 내 주위의 구성 요소를 이동합니다. 전체 크기의 그래픽을 사용하여 버튼을 만들고 버튼의 배경 이미지로 사용할 수도 있습니다 (그런 다음 titleEdgeInsets제목을 이동하는 데 사용 ).


8
서브 클래스를 구현하는 것보다 단순히 삽입을 설정하는 코드가 훨씬 적습니다. 이것이 삽입의 요점입니다. 아직 만들지 않은 하위 뷰의 프레임을 조작하는 것은 마치 해킹처럼 느껴집니다.
— Kim André Sand

6
@kimsnarf, 정말? 이미지의 크기 나 제목의 길이를 약간 변경할 때마다 삽입물을 조정하는 것이 훨씬 적은 작업 (그리고 해킹도 덜 )입니까?
— Kirk Woll

54

Raymond 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
많은 버튼을 관리해야하는 경우이 방법이 더 좋지만 하나의 버튼 만 변경하면됩니다. :)
— Pavel Yakimenko 2011 년

2
버튼 이미지가 nil이면 UIImageView가 삽입되지 않았기 때문일 수 있습니다 (iOS6.0에서 테스트 됨). imageView.image가 nil이 아닌 경우에만 프레임 편집을 고려해야합니다.
— Scakko 2013

2
이 답변에 대해 다음 개선을 제안하여 두 뷰가 중앙에 유지되도록합니다. 'CGFloat cumulativeWidth = CGRectGetWidth (imageFrame) + CGRectGetWidth (labelFrame) + 10; CGFloat exceedWidth = CGRectGetWidth (self.bounds)-cumulativeWidth; labelFrame.origin.x = exceedWidth / 2; imageFrame.origin.x = CGRectGetMaxX (labelFrame) + 10; '
— i-konov 2014

이것은 나를 위해 iOS 7에서 중단됩니다. 다른 사람? iOS 8에서 잘 작동합니다.
— rounak

1
iOS7을 전혀 지원하지 않으면 문제가 사라질 것입니다. 어쨌든 그것을 supoprt해서는 안됩니다.
— Gil Sand

30

서브 클래 싱 UIButton과 재정의는 layoutSubviews어떻습니까?

그런 다음 self.imageView& 의 위치를 ​​후 처리합니다.self.titleLabel


4
이것은 손으로 조정 한 삽입물을 사용하여 모든 것을 올바르게 배치하려는 다른 모든 조언 (위와 같은)보다 훨씬 쉽습니다.
— Steven Kramer

13

또 다른 간단한 방법 (iOS 9 만 아님)은 UIButton을 하위 클래스로 만들어이 두 메서드를 재정의하는 것입니다.

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 () :
— 조 Susnick

1
가장 좋은 방법은 : 내 소견에서 이것에 대해 이동
— DrPatience

9

앱이 '왼쪽에서 오른쪽'과 '오른쪽에서 왼쪽'을 모두 지원하는 경우 버튼에 대해 '오른쪽에서 왼쪽'을 강제하는 것은 옵션이 아닙니다.

나를 위해 일한 솔루션은 Storyboard의 버튼에 추가 할 수 있고 제약 조건 (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에서 버튼의 프레임 너비를 계산하여이 문제를 해결할 수 있습니다.


1
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

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.