source

UIButton에서 텍스트 오른쪽에 이미지를 배치하려면 어떻게 해야 합니까?

manycodes 2023. 4. 16. 15:24
반응형

UIButton에서 텍스트 오른쪽에 이미지를 배치하려면 어떻게 해야 합니까?

피할 수 있으면 서브뷰를 사용하고 싶지 않습니다.갖고 싶다UIButton배경 이미지, 텍스트 및 이미지가 포함되어 있습니다.이 때 이미지가 텍스트 왼쪽에 표시됩니다.배경 이미지, 텍스트 및 이미지 모두 다른 강조 표시 상태를 가집니다.

가장 심플한 솔루션:

iOS 10 이상, Swift:

button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

iOS 10 이전 버전, Swift/Obj-C:

button.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.titleLabel.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.imageView.transform = CGAffineTransformMakeScale(-1.0, 1.0);

iOS 9 이상, Swift: (권장)

button.semanticContentAttribute = .forceRightToLeft

제안된 답변 중 일부는 매우 창의적이고 매우 영리하지만, 가장 간단한 해결책은 다음과 같습니다.

button.semanticContentAttribute = UIApplication.shared
    .userInterfaceLayoutDirection == .rightToLeft ? .forceLeftToRight : .forceRightToLeft

그것처럼 간단해.보너스로, 이미지는 오른쪽에서 왼쪽으로 로케일에 배치됩니다.

편집: 몇 번 질문 드렸듯이 iOS 9 + 입니다.

XCODE 9용 업데이트(인터페이스 빌더 사용)

Interface Builder에서 더 쉬운 방법이 있습니다.

[ View Utilities ]> [ Symantic ]에서 UIButton 을 선택하고 다음 옵션을 선택합니다.

왼쪽에서 오른쪽으로 여기에 이미지 설명 입력 바로 그거야!멋지고 심플해!

옵션 - 두 번째 단계:

영상과 제목 사이의 간격을 조정하려면 여기서 이미지 삽입을 변경할 수 있습니다.

여기에 이미지 설명 입력

UIButton을 하위 분류할 필요가 전혀 없습니다.대신 이미지 삽입에 대해 왼쪽 상단 삽입 값을 설정하고 제목에 대해 오른쪽 작은 삽입을 설정할 수 있습니다.다음과 같은 경우:

button.imageEdgeInsets = UIEdgeInsetsMake(0., button.frame.size.width - (image.size.width + 15.), 0., 0.);
button.titleEdgeInsets = UIEdgeInsetsMake(0., 0., 0., image.size.width);

인스파이어48에게 공로를 돌리겠습니다그의 제안과 다른 질문을 보고 나는 이것을 생각해냈다.UIButton 서브클래스를 사용하여 이들 메서드를 덮어씁니다.

@implementation UIButtonSubclass

- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    CGRect frame = [super imageRectForContentRect:contentRect];
    frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) -  self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame;
}

- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    CGRect frame = [super titleRectForContentRect:contentRect];
    frame.origin.x = CGRectGetMinX(frame) - CGRectGetWidth([self imageRectForContentRect:contentRect]);
    return frame;
}

@end

제목이 바뀌면 설치 내용을 업데이트하세요.반대쪽의 등가 삽입으로 삽입물을 보정해야 합니다.

[thebutton setTitle:title forState:UIControlStateNormal];
thebutton.titleEdgeInsets = UIEdgeInsetsMake(0, -thebutton.imageView.frame.size.width, 0, thebutton.imageView.frame.size.width);
thebutton.imageEdgeInsets = UIEdgeInsetsMake(0, thebutton.titleLabel.frame.size.width, 0, -thebutton.titleLabel.frame.size.width);

합니다.Builder에서 을 Interface Builder로 합니다.Force Right-to-Left 방식을semanticContentAttribute = .forceRightToLeft그러면 텍스트 오른쪽에 이미지가 표시됩니다.

인터페이스 빌더에서는, 컨텐츠, 이미지, 타이틀의 3 부분 각각에 대해서, 엣지 인셋 for UIButton 옵션을 설정할 수 있습니다.

여기에 이미지 설명 입력 여기에 이미지 설명 입력

Xcode 8:

여기에 이미지 설명 입력

표준 버튼 이미지 뷰를 사용하지 않기로 했습니다.그것은 이동하기 위한 솔루션 제안으로 인해 해킹이 되었다고 생각했기 때문입니다.그 결과 원하는 미관을 얻을 수 있었습니다.또, 다음의 제약 조건을 변경해 버튼의 위치를 변경하는 것은 직관적입니다.

extension UIButton {
    func addRightIcon(image: UIImage) {
        let imageView = UIImageView(image: image)
        imageView.translatesAutoresizingMaskIntoConstraints = false

        addSubview(imageView)

        let length = CGFloat(15)
        titleEdgeInsets.right += length

        NSLayoutConstraint.activate([
            imageView.leadingAnchor.constraint(equalTo: self.titleLabel!.trailingAnchor, constant: 10),
            imageView.centerYAnchor.constraint(equalTo: self.titleLabel!.centerYAnchor, constant: 0),
            imageView.widthAnchor.constraint(equalToConstant: length),
            imageView.heightAnchor.constraint(equalToConstant: length)
        ])
    }
}

오른쪽 화살표 단추

업데이트: Swift 3

class ButtonIconRight: UIButton {
    override func imageRect(forContentRect contentRect:CGRect) -> CGRect {
        var imageFrame = super.imageRect(forContentRect: contentRect)
        imageFrame.origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
        return imageFrame
    }

    override func titleRect(forContentRect contentRect:CGRect) -> CGRect {
        var titleFrame = super.titleRect(forContentRect: contentRect)
        if (self.currentImage != nil) {
            titleFrame.origin.x = super.imageRect(forContentRect: contentRect).minX
        }
        return titleFrame
    }
}

Swift 2의 원래 답변:

모든 수평 정렬을 처리하는 솔루션(Swift 구현 예 포함)필요한 경우 Objective-C로 번역합니다.

class ButtonIconRight: UIButton {
    override func imageRectForContentRect(contentRect:CGRect) -> CGRect {
        var imageFrame = super.imageRectForContentRect(contentRect)
        imageFrame.origin.x = CGRectGetMaxX(super.titleRectForContentRect(contentRect)) - CGRectGetWidth(imageFrame)
        return imageFrame
    }

    override func titleRectForContentRect(contentRect:CGRect) -> CGRect {
        var titleFrame = super.titleRectForContentRect(contentRect)
        if (self.currentImage != nil) {
            titleFrame.origin.x = CGRectGetMinX(super.imageRectForContentRect(contentRect))
        }
        return titleFrame
    }
}

또, 이미지와 타이틀의 삽입에 대응하고 있는 것도 주목할 필요가 있습니다.

자송레고리 답변에서 영감을 얻어;)

UIBarButtonItem에서 이 작업을 수행해야 할 경우 뷰에서 추가 래핑을 사용해야 합니다.
으로 충분합니다.

let view = UIView()
let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
view.addSubview(button)
view.frame = button.bounds
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: view)

이거 안 돼

let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)

스스로 하세요.Xcode10, swift4,

프로그래밍 방식의 UI 설계용

여기에 이미지 설명 입력

 lazy var buttonFilter : ButtonRightImageLeftTitle = {
    var button = ButtonRightImageLeftTitle()
    button.setTitle("Playfir", for: UIControl.State.normal)
    button.setImage(UIImage(named: "filter"), for: UIControl.State.normal)
    button.backgroundColor = UIColor.red
    button.contentHorizontalAlignment = .left
    button.titleLabel?.font = UIFont.systemFont(ofSize: 16)
    return button
}()

모서리 삽입 값은 직사각형에 적용되어 해당 직사각형으로 표시되는 영역을 축소하거나 확장합니다.일반적으로 모서리 삽입은 뷰 레이아웃 중에 뷰의 프레임을 수정하는 데 사용됩니다.양의 값을 지정하면 프레임이 삽입(또는 축소)됩니다.음수 값을 지정하면 프레임이 지정된 양만큼 시작(또는 확장)됩니다.

class ButtonRightImageLeftTitle: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        guard imageView != nil else { return }

        imageEdgeInsets = UIEdgeInsets(top: 5, left: (bounds.width - 35), bottom: 5, right: 5)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: -((imageView?.bounds.width)! + 10), bottom: 0, right: 0 )

    }
}

StoryBoard UI 디자인용

여기에 이미지 설명 입력 여기에 이미지 설명 입력

iOS 15 에서는, 인셋이 없는 등, 간단하게 버튼내의 이미지 배치를 처리할 수 있는 업데이트가 제공되고 있습니다.

XIB/Storyboards: 버튼에 이미지 속성을 추가한 후 버튼 '배치' 속성을 선행/훈련/상단/하단으로 설정하기만 하면 됩니다.선행/훈련이기 때문에 RTL을 지원한다는 추가적인 장점이 있습니다.

**코드(프로그래밍 방식):** 프로그램 방식으로 버튼 구성 속성 사용

이 기능은 하위 호환성이 없으며 WWDC '21 - https://developer.apple.com/videos/play/wwdc2021/10064/?time=236에서 설명한 바와 같이 iOS15+에서만 작동합니다.

개발자 문서: https://developer.apple.com/documentation/uikit/uibutton/configuration?changes=_4

.UIButton중앙에 정렬된 콘텐츠를 제공합니다.되어 「」를 할 수 됩니다.imageEdgeInsets ★★★★★★★★★★★★★★★★★」titleEdgeInsets중요한 위치를 지정하기 위해.

여기에 이미지 설명 입력

'''UIButton커스텀 클래스를 지정하고 다음을 추가합니다.

- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    CGRect frame = [super imageRectForContentRect:contentRect];
    CGFloat imageWidth = frame.size.width;
    CGRect titleRect = CGRectZero;
    titleRect.size = [[self titleForState:self.state] sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}];
    titleRect.origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    frame.origin.x = titleRect.origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame;
}

- (CGRect)titleRectForContentRect:(CGRect)contentRect {
    CGFloat imageWidth = [self imageForState:self.state].size.width;
    CGRect frame = [super titleRectForContentRect:contentRect];
    frame.origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    return frame;
}

익스텐션 웨이

확장을 사용하여 사용자 지정 오프셋을 사용하여 오른쪽에 이미지 설정

   extension UIButton {
    func addRightImage(image: UIImage, offset: CGFloat) {
        self.setImage(image, for: .normal)
        self.imageView?.translatesAutoresizingMaskIntoConstraints = false
        self.imageView?.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true
        self.imageView?.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -offset).isActive = true
    }
}

iOS 11에서는 변환 솔루션이 동작하지 않기 때문에 새로운 접근방식을 작성하기로 했습니다.

의 조정semanticContentAttribute텍스트가 변경되어도 레이아웃을 하지 않아도, 이미지를 우측으로 선명하게 표시할 수 있습니다.그렇기 때문에 이것이 이상적인 해결책입니다.RTL을 사용하다같은 세션에서 앱의 레이아웃 방향을 변경할 수 없기 때문에 이 문제는 쉽게 해결됩니다.

그렇긴 하지만, 꽤 간단해요.

extension UIButton {
    func alignImageRight() {
        if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
            semanticContentAttribute = .forceRightToLeft
        }
        else {
            semanticContentAttribute = .forceLeftToRight
        }
    }
}

Swift - UiButton을 확장하여 다음 줄을 넣습니다.

    if let imageWidth = self.imageView?.frame.width {
        self.titleEdgeInsets = UIEdgeInsetsMake(0, -imageWidth, 0, imageWidth);
    }

    if let titleWidth = self.titleLabel?.frame.width {
        let spacing = titleWidth + 20
        self.imageEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, -spacing);
    }

Xcode 13.3으로 다음 몇 단계로 해결하였고 이미지에 패딩을 추가하였습니다.

버튼을 작성한 후 다음 절차에 따릅니다.

  1. 먼저 이미지를 정의합니다.
    let symbol = UIImage(named: "put name of your symbol here")
    
  2. 그럼 인viewDidLoad버튼을 작성한 위치에서 위에서 정의한 이미지를 1로 초기화하여 이미지를 버튼에 추가하고 속성을 설정합니다.
    button.setImage(symbol, for: .normal)
    button.semanticContentAttribute = .forceRightToLeft
    button.configuration?.imagePadding = 2
    

뷰에 버튼을 추가하는 것도 잊지 마세요.

Piotr Tomasik의 우아한 솔루션을 기반으로: 버튼 라벨과 이미지 사이에도 약간의 간격을 두고 싶다면 다음과 같이 엣지 삽입에 포함시키십시오(내 코드를 여기에 복사하면 완벽하게 작동합니다).

    CGFloat spacing          = 3;
    CGFloat insetAmount      = 0.5 * spacing;

    // First set overall size of the button:
    button.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
    [button sizeToFit];

    // Then adjust title and image insets so image is flipped to the right and there is spacing between title and image:
    button.titleEdgeInsets   = UIEdgeInsetsMake(0, -button.imageView.frame.size.width - insetAmount, 0,  button.imageView.frame.size.width  + insetAmount);
    button.imageEdgeInsets   = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width + insetAmount, 0, -button.titleLabel.frame.size.width - insetAmount);

Piotr의 솔루션에 감사드립니다!

에릭

@Piotr의 답변을 받아 Swift 확장자로 만들었습니다.버튼의 사이즈가 올바르게 설정되도록, 반드시 이미지와 제목을 설정해 주세요.

 extension UIButton {
    
    /// Makes the ``imageView`` appear just to the right of the ``titleLabel``.
    func alignImageRight() {
        if let titleLabel = self.titleLabel, imageView = self.imageView {
            // Force the label and image to resize.
            titleLabel.sizeToFit()
            imageView.sizeToFit()
            imageView.contentMode = .ScaleAspectFit
            
            // Set the insets so that the title appears to the left and the image appears to the right. 
            // Make the image appear slightly off the top/bottom edges of the button.
            self.titleEdgeInsets = UIEdgeInsets(top: 0, left: -1 * imageView.frame.size.width,
                bottom: 0, right: imageView.frame.size.width)
            self.imageEdgeInsets = UIEdgeInsets(top: 4, left: titleLabel.frame.size.width,
                bottom: 4, right: -1 * titleLabel.frame.size.width)
          }
        }
     }

서브클래싱 및 오버라이드 레이아웃 서브뷰가 최선의 방법일 것입니다.

출처: iPhone UIButton - 이미지 위치

인셋을 사용하지 않고 원하는 것을 할 수 있는 신속한 옵션:

class RightImageButton: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let  textSize = titleLabel?.intrinsicContentSize(),
                imageSize = imageView?.intrinsicContentSize() {
            let wholeWidth = textSize.width + K.textImageGap + imageSize.width
            titleLabel?.frame = CGRect(
                x: round(bounds.width/2 - wholeWidth/2),
                y: 0,
                width: ceil(textSize.width),
                height: bounds.height)
            imageView?.frame = CGRect(
                x: round(bounds.width/2 + wholeWidth/2 - imageSize.width),
                y: RoundRetina(bounds.height/2 - imageSize.height/2),
                width: imageSize.width,
                height: imageSize.height)
        }
    }

    struct K {
        static let textImageGap: CGFloat = 5
    }

}

여기서 설명한 솔루션은 자동 레이아웃을 활성화하면 작동을 멈춥니다.난 나만의 방법을 생각해내야 했다.

서브클래스 UIButton 및 오버라이드layoutSubviews방법:

//
//  MIThemeButtonImageAtRight.m
//  Created by Lukasz Margielewski on 7/9/13.
//

#import "MIThemeButtonImageAtRight.h"

static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets);

@implementation MIThemeButtonImageAtRight

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGRect contentFrame = CGRectByApplyingUIEdgeInsets(self.bounds, self.contentEdgeInsets);

    CGRect frameIcon = self.imageView.frame;
    CGRect frameText = self.titleLabel.frame;

    frameText.origin.x = CGRectGetMinX(contentFrame) + self.titleEdgeInsets.left;
    frameIcon.origin.x = CGRectGetMaxX(contentFrame) - CGRectGetWidth(frameIcon);

    self.imageView.frame = frameIcon;
    self.titleLabel.frame = frameText;
}

@end

static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets){

    CGRect f = frame;

    f.origin.x += insets.left;
    f.size.width -= (insets.left + insets.right);
    f.origin.y += (insets.top);
    f.size.height -= (insets.top + insets.bottom);

    return f;

}

결과:

여기에 이미지 설명 입력

3.0 재송레고리에서 제공하는 신속한 이행 솔루션

class ButtonIconRight: UIButton {
        override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
            var imageFrame = super.imageRect(forContentRect: contentRect)
           imageFrame.origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
        return imageFrame
        }

        override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
            var titleFrame = super.titleRect(forContentRect: contentRect)
            if (self.currentImage != nil) {
                titleFrame.origin.x = super.imageRect(forContentRect: contentRect).minX
            }
            return titleFrame
        }

Xcode 11.4 Swift 5.2

다음과 같은 쉐브론으로 뒤로 버튼 스타일을 미러링하려는 사용자:

여기에 이미지 설명 입력

import UIKit

class NextBarButton: UIBarButtonItem {

    convenience init(target: Any, selector: Selector) {

        // Create UIButton
        let button = UIButton(frame: .zero)

        // Set Title
        button.setTitle("Next", for: .normal)
        button.setTitleColor(.systemBlue, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 17)

        // Configure Symbol
        let config = UIImage.SymbolConfiguration(pointSize: 19.0, weight: .semibold, scale: .large)
        let image = UIImage(systemName: "chevron.right", withConfiguration: config)
        button.setImage(image, for: .normal)

        // Add Target
        button.addTarget(target, action: selector, for: .touchUpInside)

        // Put the Image on the right hand side of the button
        // Credit to liau-jian-jie for this part
        button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)

        // Customise spacing to match system Back button
        button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: -18.0, bottom: 0.0, right: 0.0)
        button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -12.0, bottom: 0.0, right: 0.0)

        self.init(customView: button)
    }
}

구현:

override func viewDidLoad() {
    super.viewDidLoad()
    let nextButton = NextBarButton(target: self, selector: #selector(nextTapped))
    navigationItem.rightBarButtonItem = nextButton
}

@objc func nextTapped() {
    // your code
}

이 작업은 swift 5.2에서 수행합니다.

let sizeOfTitle: CGFloat = 80
let sizeOfImage: CGFloat = 20
yourButton.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -sizeOfImage , bottom: 0.0, right: sizeOfImage)
yourButton.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: sizeOfTitle, bottom: 0.0, right: -sizeOfTitle)

스위프트 3:

open override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    var frame = super.imageRect(forContentRect: contentRect)
    let  imageWidth = frame.size.width
    var titleRect = CGRect.zero
    titleRect.size = self.title(for: self.state)!.size(attributes: [NSFontAttributeName: self.titleLabel!.font])
    titleRect.origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    frame.origin.x = titleRect.origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
    return frame
}

open override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    var frame = super.titleRect(forContentRect: contentRect)
    if let imageWidth = self.image(for: self.state)?.size.width {
        frame.origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
    }
    return frame
}

제약은 어떻습니까?semantic Content Attribute와는 달리 의미론은 변경되지 않습니다.다음과 같은 경우가 있습니다.

 button.rightAnchorconstraint(equalTo: button.rightAnchor).isActive = true

또는 목표-C:

[button.imageView.rightAnchor constraintEqualToAnchor:button.rightAnchor].isActive = YES;

경고:미테스트, iOS 9+

인터넷을 통해 여러 솔루션을 시도했지만 정확한 요건을 충족하지 못했습니다.그래서 커스텀 유틸리티 코드를 작성하게 되었습니다.앞으로 누군가를 돕기 위해 글을 올리는 것.Swift 4.2에서 테스트 완료

// This function should be called in/after viewDidAppear to let view render
    func addArrowImageToButton(button: UIButton, arrowImage:UIImage = #imageLiteral(resourceName: "my_image_name") ) {
        let btnSize:CGFloat = 32
        let imageView = UIImageView(image: arrowImage)
        let btnFrame = button.frame
        imageView.frame = CGRect(x: btnFrame.width-btnSize-8, y: btnFrame.height/2 - btnSize/2, width: btnSize, height: btnSize)
        button.addSubview(imageView)
        //Imageview on Top of View
        button.bringSubviewToFront(imageView)
    }

이 문제에 대해서는 "UIImage view를 포함한 라벨" 내에 UIView를 생성하여 UIView 클래스를 UIControl로 설정하고 IBAction을 측면 탭업으로 생성할 수 있습니다.

여기에 이미지 설명 입력

언급URL : https://stackoverflow.com/questions/7100976/how-do-i-put-the-image-on-the-right-side-of-the-text-in-a-uibutton

반응형