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

가치있는 것을 위해, 마법의 숫자를 사용하지 않고 텍스트 위에 이미지를 배치하는 일반적인 해결책이 있습니다. 다음 코드는 구식이므로 아래 업데이트 된 버전 중 하나를 사용해야합니다 .

// 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);

스위프트 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를 사용하는 것으로 보입니다.
Dan Jackson

5
@ Heemang과 Dan Jackson, 나는 당신의 제안을 직접 테스트하지 않고 통합하고 있습니다. 필자는 원래 iOS 4 용으로 이것을 쓴 것이 우스운 일이라고 생각합니다.이 많은 버전 이후에도 우리는 여전히 분명한 기능을 얻기 위해 Apple의 레이아웃 알고리즘을 리버스 엔지니어링해야합니다. 또는 적어도 일관성있는 upvotes 스트림과 아래의 hackish 답변 (모욕이 없음)에서 더 나은 솔루션이 아직 없다고 가정합니다.
Jesse Crossen

5
iOS8에서는 버튼 텍스트가 변경되는 경우 특히 button.currentTitle대신 사용 하는 것이 더 좋습니다 button.titleLabel.text. currentTitle입력 titleLabel.text이 잘못 될 수 있으므로 변경 속도가 느릴 수 있습니다.
mjangda

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 자동 레이아웃을 사용해야 여전히 올바르게 작동하는지 해야합니다.

UIKit 컨트롤을 서브 클래스 화해서는 안되기 때문에 UIButton 서브 클래스의 모든 솔루션이 기술적으로 불법이라고 생각합니다. 즉, 이론 상으로는 향후 릴리스에서 중단 될 수 있습니다.


iOS9에서 테스트. 이미지는 중앙에 표시되지만 텍스트는 왼쪽에 나타납니다. (
endavid

13

편집 : 스위프트 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이되어 원하는만큼 많은 행이 될 수 없어야합니까?
벤 Lachman

제 경우에는 최대 두 줄만 원했습니다. 그렇지 않으면 이미지의 전체 크기에 문제가있을 수 있습니다.
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에서 크기 관리자로 이동되었습니다. 스위치가 언제 발생했는지 100 % 명확하지 않지만 속성 관리자에서 삽입 된 정보를 찾을 수없는 경우 크기 관리자를 검토해야합니다. 아래는 새로운 삽입 화면의 샘플입니다 (11.5 현재 크기 속성 관리자 상단에 위치).

insets_moved_to_size_inspector

원래 답변

다른 답변에는 아무런 문제가 없지만 코드 제로 줄을 사용하여 Xcode 내에서 동일한 동작을 시각적으로 수행 할 수 있다는 점에 주목하고 싶었습니다. 이 솔루션은 계산 된 값이 필요하지 않거나 스토리 보드 / xib로 빌드하는 경우에 유용합니다 (그렇지 않으면 다른 솔루션이 적용됨).

참고-OP의 질문은 코드가 필요한 질문이라는 것을 알고 있습니다. 나는이 답변을 완전성과 스토리 보드 / xibs를 사용하는 사람들을위한 논리적 대안으로 제공하고 있습니다.

가장자리 삽입을 사용하여 버튼의 이미지, 제목 및 내용보기의 간격을 수정하려면 버튼 / 컨트롤을 선택하고 속성 관리자를 열 수 있습니다. 인스펙터의 중앙을 향해 아래로 스크롤하여 Edge insets 섹션을 찾으십시오.

에지 인셋

제목, 이미지 또는 컨텐츠보기의 특정 모서리 삽입물에 액세스하고 수정할 수도 있습니다.

메뉴 옵션


내가 이해하지 못하는 것은 스토리 보드에 어떤 값으로 음수를 입력 할 수없는 이유입니다.
Daniel T.

최신 스위프트 버전에서도 작동합니까? Edge 속성을 찾을 수 없습니다
3

@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 4Jesse 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/…
Bohdan 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

3

사용하기 button.titleLabel.frame.size.width좋은 단지 한 라벨을 작동하는 것은 잘 리게하는 짧은 충분하다. 레이블 텍스트가 잘 리면 위치가 작동하지 않습니다. 취득

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

레이블 텍스트가 잘린 경우에도 작동합니다.


당신은 botton 오타가 있습니다.
Bhimbim

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

0

텍스트와 이미지를 가로로 가운데에 맞추기를 원한다고 가정하면 텍스트 위의 이미지 : 인터페이스 빌더에서 텍스트를 가운데에 배치하고 맨 위 삽입 (이미지를위한 공간)을 추가하십시오. (왼쪽 삽입은 0으로 두십시오). 인터페이스 빌더를 사용하여 이미지를 선택하십시오. 실제 위치는 코드에서 설정되므로 IB에서 문제가 발생하지 않을까 걱정하지 마십시오. 위의 다른 답변과 달리 이것은 현재 지원되는 모든 iOS 버전 (5, 6 및 7)에서 실제로 작동합니다.

코드에서 이미지를 가져온 후 버튼의 ImageView를 버리고 (버튼의 이미지를 null로 설정하여) (필요한 경우 자동으로 텍스트를 가운데에 배치합니다). 그런 다음 동일한 프레임 크기와 이미지로 자신의 ImageView를 인스턴스화하고 중간에 배치하십시오.

이 방법으로 인터페이스 빌더에서 이미지를 계속 선택할 수 있습니다 (시뮬레이터에서와 같이 IB에서 정렬되지는 않지만 다른 솔루션은 지원되는 모든 iOS 버전에서 호환되지 않습니다)


0

뷰 생성자에서 이미지 크기와 텍스트 너비를 얻을 수 없으므로이 작업을 수행하는 데 어려움을 겪었습니다. Jesse의 답변에 대한 두 가지 사소한 변경 사항 이 저에게 효과적 이었습니다.

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.