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.