imageEdgeInsets 및 titleEdgeInsets와의 UIButton 텍스트 및 이미지 정렬
두 줄의 텍스트 중 아이콘은 이미지와 텍스트 시작 사이에 2~3픽셀 정도의 간격을 두고 배치하고 싶습니다.컨트롤 자체는 수평으로 중앙에 정렬되어 있습니다(인터페이스 빌더에서 설정).
버튼은 다음과 같습니다.
| |
|[Image] Add To |
| Favorites |
contentEdgeInset, imageEdgeInset 및 titleEdgeInset을 사용하여 설정하려고 합니다.음의 값은 엣지를 확장하고 양의 값은 엣지를 축소하여 중심에 가깝게 이동한다는 것을 알고 있습니다.
나는 시도했다.
[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];
이게 잘 안 나오네요.값을 조정하고 있습니다만, 왼쪽의 삽입치의 -5에서 -10으로 하면, 예상대로 움직이지 않는 것 같습니다. -10은 텍스트를 왼쪽으로 스쿠트 하기 때문에 -5가 왼쪽에서 반쯤 스쿠트 할 줄 알았는데, 안 되더라고요.
인셉트 뒤에 있는 논리가 뭐죠?이미지 배치 및 관련 용어에 익숙하지 않습니다.
저는 이 SO 질문을 참고 자료로 사용했는데, 제 가치관이 맞지 않습니다.UIButton: imageEdgeInsets 및 titleEdgeInsets를 사용하여 이미지와 텍스트를 중앙에 배치하는 방법
이 파티에 조금 늦었지만, 덧붙일 유용한 것이 있을 것 같아요.
언급했듯이 이 Kekoa를 존중하지 될 수 .sizeToFit또는, 보다 중요한 것은, 본래의 사이즈가 되었을 때에, 버튼이 컨텐츠를 클리핑 하는 원인이 되는 것입니다.
하지만 먼저,
하겠습니다.imageEdgeInsets ★★★★★★★★★★★★★★★★★」titleEdgeInsets 삭제:
의 문서에는 다음과 같은 내용이 포함되어 있습니다.
이 속성을 사용하여 단추 이미지의 유효한 도면 사각형의 크기를 조정하고 위치를 변경할 수 있습니다.4개의 삽입(위, 왼쪽, 아래, 오른쪽) 각각에 다른 값을 지정할 수 있습니다.양의 값은 해당 가장자리를 축소하거나 삽입하여 버튼의 중앙으로 이동합니다.음의 값은 해당 에지를 확장하거나 아웃셋합니다.
이 문서는 제목도 없고 이미지만 있는 것으로 알고 있습니다.하면 훨씬 , 하는지 알 수 있습니다.UIEdgeInsets보통 한다.기본적으로 이미지의 프레임(또는 제목,titleEdgeInsets으로, 는 포지티브인 경우 안쪽으로, 네거티브인 경우 바깥쪽으로 이동합니다.
좋아요, 그래서요?
가고 있어요!이미지와 제목을 설정하는 기본 설정은 다음과 같습니다(버튼 테두리는 위치를 표시하기 위해 녹색으로 표시됩니다).

이미지와 제목 사이에 간격을 두고 어느 쪽도 찌그러지지 않도록 하려면 이미지와 제목 각각에 2개씩 4개의 서로 다른 삽입물을 설정해야 합니다.그 이유는 이러한 요소의 프레임 크기를 변경하지 않고 위치만 변경하고 싶기 때문입니다.이렇게 생각하기 시작하면 Kekoa의 뛰어난 카테고리에 대한 필요한 변화가 명확해진다.
@implementation UIButton(ImageTitleCentering)
- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
CGFloat insetAmount = spacing / 2.0;
self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
}
@end
하지만 잠깐, 내가 그렇게 했을 때, 난 이렇게 느꼈어.

아 맞다!깜빡했네요, 의사 선생님이 경고해 주셨어요.그들은 부분적으로 다음과 같이 말한다.
이 속성은 레이아웃 중에 이미지를 배치하는 데만 사용됩니다.은 이 하여 결정하지 .
intrinsicContentSize★★★★★★★★★★★★★★★★★」sizeThatFits:.
하지만 도울 수 있는 재산이 있어요 그게 바로contentEdgeInsets그 문서에는 부분적으로 다음과 같은 내용이 있습니다.
은 이 하여 ""를 결정합니다.
intrinsicContentSize★★★★★★★★★★★★★★★★★」sizeThatFits:.
좋아요.이 카테고리를 다시 한번 조정해 보겠습니다.
@implementation UIButton(ImageTitleCentering)
- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
CGFloat insetAmount = spacing / 2.0;
self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
self.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
}
@end
그리고 당신은 무엇을 얻나요?

내가 보기엔 승자 같은데.
스위프트에서 일하면서 아무 생각도 하기 싫다고?다음은 Swift 확장의 최종 버전입니다.
extension UIButton {
func centerTextAndImage(spacing: CGFloat) {
let insetAmount = spacing / 2
let isRTL = UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft
if isRTL {
imageEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
titleEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
contentEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: -insetAmount)
} else {
imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
}
}
}
에 관한 문서에 동의합니다.imageEdgeInsets ★★★★★★★★★★★★★★★★★」titleEdgeInsets더 낫겠지만 시행착오를 겪지 않고 올바른 위치를 잡는 방법을 알아냈어요.
일반적인 생각은 이 질문에 있지만, 텍스트와 이미지 모두를 중심에 두고 싶은 경우입니다.이미지와 텍스트가 개별적으로 중앙에 배치되는 것이 아니라 이미지와 텍스트가 하나의 엔티티로 중앙에 배치되는 것이 좋습니다.이것은 사실 UIButton이 이미 하고 있는 일이기 때문에 우리는 단지 간격을 조정하기만 하면 된다.
CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
또, 사용하기 쉽도록, 이것을 UIButton용의 카테고리는 다음과 같습니다.
UIButton+Position.h
@interface UIButton(ImageTitleCentering)
-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;
@end
UIButton+위치.m
@implementation UIButton(ImageTitleCentering)
-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}
@end
이제 내가 해야 할 일은
[button centerButtonAndImageWithSpacing:10];
매번 필요한 걸 얻어요엣지 삽입을 수동으로 조작할 필요가 없어집니다.
편집: 이미지와 텍스트의 스왑
코멘트의 @Javal에 대한 응답
동일한 메커니즘을 사용하여 이미지와 텍스트를 교환할 수 있습니다.스와프를 실시하려면 , 음의 간격을 사용하는 것만으로, 텍스트와 이미지의 너비도 포함할 수 있습니다.이를 위해서는 프레임을 인식하고 레이아웃을 이미 수행해야 합니다.
[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];
물론 당신은 아마도 이것을 위한 좋은 방법을 만들고 싶을 것이고, 잠재적으로 두 번째 카테고리 방법을 추가할 수 있습니다. 이것은 독자들에게 연습으로 남겨집니다.
그리고 이런 걸 만들고 싶다면

당신은 필요하다
1. 버튼의 수평과 수직 정렬을 다음과 같이 설정합니다.

설정하세요.
UIImageEdgeInsetsCGSize buttonSize = button.frame.size; NSString *buttonTitle = button.titleLabel.text; CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }]; UIImage *buttonImage = button.imageView.image; CGSize buttonImageSize = buttonImage.size; CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText, (buttonSize.width - buttonImageSize.width) / 2, 0,0)]; [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText, titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width + (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width, 0,0)];
그러면 제목과 이미지가 버튼으로 정렬됩니다.
또한 각 레이아웃에서 이 정보를 업데이트하십시오.
재빠르다
import UIKit
extension UIButton {
// MARK: - UIButton+Aligment
func alignContentVerticallyByCenter(offset:CGFloat = 10) {
let buttonSize = frame.size
if let titleLabel = titleLabel,
let imageView = imageView {
if let buttonTitle = titleLabel.text,
let image = imageView.image {
let titleString:NSString = NSString(string: buttonTitle)
let titleSize = titleString.sizeWithAttributes([
NSFontAttributeName : titleLabel.font
])
let buttonImageSize = image.size
let topImageOffset = (buttonSize.height - (titleSize.height + buttonImageSize.height + offset)) / 2
let leftImageOffset = (buttonSize.width - buttonImageSize.width) / 2
imageEdgeInsets = UIEdgeInsetsMake(topImageOffset,
leftImageOffset,
0,0)
let titleTopOffset = topImageOffset + offset + buttonImageSize.height
let leftTitleOffset = (buttonSize.width - titleSize.width) / 2 - image.size.width
titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset,
leftTitleOffset,
0,0)
}
}
}
}
인터페이스 빌더에서[UIButton ]-> [ Attributes Inspector ]-> [ Edge = ]를 선택합니다.엣지 삽입 제목 지정 및 수정
Xcode 8.0 에서는, 간단하게 변경할 수 있습니다.insets사이즈 인스펙터입니다.
[UIButton ]-> [ Attributes Inspector ]-> [ size inspector ]를 선택하여 콘텐츠, 이미지 및 제목 삽입을 변경합니다.
는 그냥 을 '아울러 주세요'로 .Force Right-to-left inspector ]으로 합니다.
이것을 사용하면, 큰 트러블을 피할 수고를 피할 수 있습니다.
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
그러면 모든 콘텐츠가 자동으로 왼쪽(또는 원하는 위치)에 정렬됩니다.
스위프트 3:
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;
저도 이 파티에 조금 늦었지만, 덧붙여야 할 유용한 것이 있다고 생각합니다. :o)
는 작했니 a 를 만들었다.UIButton버튼의 이미지가 배치될 위치를 수직 또는 수평으로 선택할 수 있는 서브클래스입니다.
즉, 다음과 같은 종류의 버튼을 만들 수 있습니다.
클래스에서의 이러한 버튼 작성 방법에 대한 자세한 내용은 다음과 같습니다.
func makeButton (imageVerticalAlignment:LayoutableButton.VerticalAlignment, imageHorizontalAlignment:LayoutableButton.HorizontalAlignment, title:String) -> LayoutableButton {
let button = LayoutableButton ()
button.imageVerticalAlignment = imageVerticalAlignment
button.imageHorizontalAlignment = imageHorizontalAlignment
button.setTitle(title, for: .normal)
// add image, border, ...
return button
}
let button1 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .left, title: "button1")
let button2 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .right, title: "button2")
let button3 = makeButton(imageVerticalAlignment: .top, imageHorizontalAlignment: .center, title: "button3")
let button4 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button4")
let button5 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button5")
button5.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
두 가지 했습니다. 즉, 2가지 속성을 추가했습니다.imageVerticalAlignment ★★★★★★★★★★★★★★★★★」imageHorizontalAlignment이 전혀 하지 마십시오!
'아주 좋다'라는도 추가했습니다.imageToTitleSpacing제목과 이미지 사이의 공간을 조정할 수 있습니다.
는 '어울리다'를 사용하고 때이 잘 합니다.imageEdgeInsets,titleEdgeInsets ★★★★★★★★★★★★★★★★★」contentEdgeInsets직접 또는 새 레이아웃 속성과 함께 사용할 수 있습니다.
@ravron의 설명대로 (빨간색 테두리가 표시되어 있는 것처럼) 버튼의 내용을 정확하게 하기 위해 노력하고 있습니다.
Interface Builder에서도 사용할 수 있습니다.
- UIButton 작성
- 버튼 클래스 변경
- "중앙", "위", "아래", "왼쪽" 또는 "오른쪽"을 사용하여 레이아웃 가능 속성 조정
코드(gist)는 다음과 같습니다.
@IBDesignable
class LayoutableButton: UIButton {
enum VerticalAlignment : String {
case center, top, bottom, unset
}
enum HorizontalAlignment : String {
case center, left, right, unset
}
@IBInspectable
var imageToTitleSpacing: CGFloat = 8.0 {
didSet {
setNeedsLayout()
}
}
var imageVerticalAlignment: VerticalAlignment = .unset {
didSet {
setNeedsLayout()
}
}
var imageHorizontalAlignment: HorizontalAlignment = .unset {
didSet {
setNeedsLayout()
}
}
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageVerticalAlignment' instead.")
@IBInspectable
var imageVerticalAlignmentName: String {
get {
return imageVerticalAlignment.rawValue
}
set {
if let value = VerticalAlignment(rawValue: newValue) {
imageVerticalAlignment = value
} else {
imageVerticalAlignment = .unset
}
}
}
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageHorizontalAlignment' instead.")
@IBInspectable
var imageHorizontalAlignmentName: String {
get {
return imageHorizontalAlignment.rawValue
}
set {
if let value = HorizontalAlignment(rawValue: newValue) {
imageHorizontalAlignment = value
} else {
imageHorizontalAlignment = .unset
}
}
}
var extraContentEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
override var contentEdgeInsets: UIEdgeInsets {
get {
return super.contentEdgeInsets
}
set {
super.contentEdgeInsets = newValue
self.extraContentEdgeInsets = newValue
}
}
var extraImageEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
override var imageEdgeInsets: UIEdgeInsets {
get {
return super.imageEdgeInsets
}
set {
super.imageEdgeInsets = newValue
self.extraImageEdgeInsets = newValue
}
}
var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
override var titleEdgeInsets: UIEdgeInsets {
get {
return super.titleEdgeInsets
}
set {
super.titleEdgeInsets = newValue
self.extraTitleEdgeInsets = newValue
}
}
//Needed to avoid IB crash during autolayout
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.imageEdgeInsets = super.imageEdgeInsets
self.titleEdgeInsets = super.titleEdgeInsets
self.contentEdgeInsets = super.contentEdgeInsets
}
override func layoutSubviews() {
if let imageSize = self.imageView?.image?.size,
let font = self.titleLabel?.font,
let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) {
var _imageEdgeInsets = UIEdgeInsets.zero
var _titleEdgeInsets = UIEdgeInsets.zero
var _contentEdgeInsets = UIEdgeInsets.zero
let halfImageToTitleSpacing = imageToTitleSpacing / 2.0
switch imageVerticalAlignment {
case .bottom:
_imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
_imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
_titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
_titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
_contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
_contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
case .top:
_imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
_imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
_titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
_titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
_contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
_contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
case .center:
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
break
case .unset:
break
}
switch imageHorizontalAlignment {
case .left:
_imageEdgeInsets.left = -halfImageToTitleSpacing
_imageEdgeInsets.right = halfImageToTitleSpacing
_titleEdgeInsets.left = halfImageToTitleSpacing
_titleEdgeInsets.right = -halfImageToTitleSpacing
_contentEdgeInsets.left = halfImageToTitleSpacing
_contentEdgeInsets.right = halfImageToTitleSpacing
case .right:
_imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
_imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
_titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
_titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
_contentEdgeInsets.left = halfImageToTitleSpacing
_contentEdgeInsets.right = halfImageToTitleSpacing
case .center:
_imageEdgeInsets.left = textSize.width / 2.0
_imageEdgeInsets.right = -textSize.width / 2.0
_titleEdgeInsets.left = -imageSize.width / 2.0
_titleEdgeInsets.right = imageSize.width / 2.0
_contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
_contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
case .unset:
break
}
_contentEdgeInsets.top += extraContentEdgeInsets.top
_contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
_contentEdgeInsets.left += extraContentEdgeInsets.left
_contentEdgeInsets.right += extraContentEdgeInsets.right
_imageEdgeInsets.top += extraImageEdgeInsets.top
_imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
_imageEdgeInsets.left += extraImageEdgeInsets.left
_imageEdgeInsets.right += extraImageEdgeInsets.right
_titleEdgeInsets.top += extraTitleEdgeInsets.top
_titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
_titleEdgeInsets.left += extraTitleEdgeInsets.left
_titleEdgeInsets.right += extraTitleEdgeInsets.right
super.imageEdgeInsets = _imageEdgeInsets
super.titleEdgeInsets = _titleEdgeInsets
super.contentEdgeInsets = _contentEdgeInsets
} else {
super.imageEdgeInsets = extraImageEdgeInsets
super.titleEdgeInsets = extraTitleEdgeInsets
super.contentEdgeInsets = extraContentEdgeInsets
}
super.layoutSubviews()
}
}
스위프트 4.x
extension UIButton {
func centerTextAndImage(spacing: CGFloat) {
let insetAmount = spacing / 2
let writingDirection = UIApplication.shared.userInterfaceLayoutDirection
let factor: CGFloat = writingDirection == .leftToRight ? 1 : -1
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
}
}
사용방법:
button.centerTextAndImage(spacing: 10.0)
업데이트된 내용에 따라 답변을 업데이트하겠습니다.Xcode 13.
이미지와 텍스트 정렬을 위해 확장자나 코드 한 줄을 사용할 필요가 없습니다.Xcode는 Attributes 탭에 아래 이미지와 같이 사전 정의된 속성을 제공합니다.
배치 속성에는 4개의 이미지 속성이 있습니다.Top, Bottom, Leading, and Trailing
계정 로케일 변경에 대한 Riley Avron의 응답에 대한 작은 추가:
extension UIButton {
func centerTextAndImage(spacing: CGFloat) {
let insetAmount = spacing / 2
let writingDirection = UIApplication.sharedApplication().userInterfaceLayoutDirection
let factor: CGFloat = writingDirection == .LeftToRight ? 1 : -1
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
}
}
인터페이스 빌더 솔루션
XCode 13.1과 iOS 15 이상에서는 상황이 변화하고 있습니다.Size inspector인스톨에 영향을 주지 않습니다.대신Attribute inspector있다Padding그리고.Content insets바람직한 효과를 가져오는 속성
이전 버전과의 호환성을 유지하기 위해서는 다음 위치에서 inset을 수행해야 합니다.Size inspector@ravron의 말대로.IB에서는 다음 조합을 수행해야 합니다.
- 이미지와 제목 사이에 8pt의 거리를 두고 싶다고 가정해 봅시다.
- 제목 왼쪽을 8pt로 추가
- 그러면 텍스트가 오른쪽에서 잘리므로 제목에 -8pt 오른쪽 삽입을 추가하는 것과 균형을 맞춰야 합니다.
- 그러면 버튼의 오른쪽 삽입도 8pt만큼 오른쪽 삽입을 늘려야 합니다.
- 완료! 버튼은 iOS 14 및 15에 매우 적합합니다.
인iOS 15+UIButton을 사용할 수 있습니다.설정:
var configuration = button.configuration
configuration?.imagePadding = 16
configuration?.titlePadding = 10
button.configuration = configuration
나는 코드를 낮게 쓴다.제품 버전에서는 잘 동작합니다.Supprot Swift 4.2 +
extension UIButton{
enum ImageTitleRelativeLocation {
case imageUpTitleDown
case imageDownTitleUp
case imageLeftTitleRight
case imageRightTitleLeft
}
func centerContentRelativeLocation(_ relativeLocation:
ImageTitleRelativeLocation,
spacing: CGFloat = 0) {
assert(contentVerticalAlignment == .center,
"only works with contentVerticalAlignment = .center !!!")
guard (title(for: .normal) != nil) || (attributedTitle(for: .normal) != nil) else {
assert(false, "TITLE IS NIL! SET TITTLE FIRST!")
return
}
guard let imageSize = self.currentImage?.size else {
assert(false, "IMGAGE IS NIL! SET IMAGE FIRST!!!")
return
}
guard let titleSize = titleLabel?
.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) else {
assert(false, "TITLELABEL IS NIL!")
return
}
let horizontalResistent: CGFloat
// extend contenArea in case of title is shrink
if frame.width < titleSize.width + imageSize.width {
horizontalResistent = titleSize.width + imageSize.width - frame.width
print("horizontalResistent", horizontalResistent)
} else {
horizontalResistent = 0
}
var adjustImageEdgeInsets: UIEdgeInsets = .zero
var adjustTitleEdgeInsets: UIEdgeInsets = .zero
var adjustContentEdgeInsets: UIEdgeInsets = .zero
let verticalImageAbsOffset = abs((titleSize.height + spacing) / 2)
let verticalTitleAbsOffset = abs((imageSize.height + spacing) / 2)
switch relativeLocation {
case .imageUpTitleDown:
adjustImageEdgeInsets.top = -verticalImageAbsOffset
adjustImageEdgeInsets.bottom = verticalImageAbsOffset
adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2
adjustTitleEdgeInsets.top = verticalTitleAbsOffset
adjustTitleEdgeInsets.bottom = -verticalTitleAbsOffset
adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2
adjustContentEdgeInsets.top = spacing
adjustContentEdgeInsets.bottom = spacing
adjustContentEdgeInsets.left = -horizontalResistent
adjustContentEdgeInsets.right = -horizontalResistent
case .imageDownTitleUp:
adjustImageEdgeInsets.top = verticalImageAbsOffset
adjustImageEdgeInsets.bottom = -verticalImageAbsOffset
adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2
adjustTitleEdgeInsets.top = -verticalTitleAbsOffset
adjustTitleEdgeInsets.bottom = verticalTitleAbsOffset
adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2
adjustContentEdgeInsets.top = spacing
adjustContentEdgeInsets.bottom = spacing
adjustContentEdgeInsets.left = -horizontalResistent
adjustContentEdgeInsets.right = -horizontalResistent
case .imageLeftTitleRight:
adjustImageEdgeInsets.left = -spacing / 2
adjustImageEdgeInsets.right = spacing / 2
adjustTitleEdgeInsets.left = spacing / 2
adjustTitleEdgeInsets.right = -spacing / 2
adjustContentEdgeInsets.left = spacing
adjustContentEdgeInsets.right = spacing
case .imageRightTitleLeft:
adjustImageEdgeInsets.left = titleSize.width + spacing / 2
adjustImageEdgeInsets.right = -titleSize.width - spacing / 2
adjustTitleEdgeInsets.left = -imageSize.width - spacing / 2
adjustTitleEdgeInsets.right = imageSize.width + spacing / 2
adjustContentEdgeInsets.left = spacing
adjustContentEdgeInsets.right = spacing
}
imageEdgeInsets = adjustImageEdgeInsets
titleEdgeInsets = adjustTitleEdgeInsets
contentEdgeInsets = adjustContentEdgeInsets
setNeedsLayout()
}
}
신속한 5.3 및 @ravron에서 영감을 얻은 답변:
extension UIButton {
/// Fits the image and text content with a given spacing
/// - Parameters:
/// - spacing: Spacing between the Image and the text
/// - contentXInset: The spacing between the view to the left image and the right text to the view
func setHorizontalMargins(imageTextSpacing: CGFloat, contentXInset: CGFloat = 0) {
let imageTextSpacing = imageTextSpacing / 2
contentEdgeInsets = UIEdgeInsets(top: 0, left: (imageTextSpacing + contentXInset), bottom: 0, right: (imageTextSpacing + contentXInset))
imageEdgeInsets = UIEdgeInsets(top: 0, left: -imageTextSpacing, bottom: 0, right: imageTextSpacing)
titleEdgeInsets = UIEdgeInsets(top: 0, left: imageTextSpacing, bottom: 0, right: -imageTextSpacing)
}
}
뷰에서 이미지에 수평 여백을 추가하고 라벨에서 뷰에 수평 여백을 추가합니다.
다음은 imageEdgeInsets 사용 방법의 간단한 예입니다. 이렇게 하면 30x30 버튼에 히타블 영역이 10픽셀 확대됩니다(50x50).
var expandHittableAreaAmt : CGFloat = 10
var buttonWidth : CGFloat = 30
var button = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
button.frame = CGRectMake(0, 0, buttonWidth+expandHittableAreaAmt, buttonWidth+expandHittableAreaAmt)
button.imageEdgeInsets = UIEdgeInsetsMake(expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt)
button.setImage(UIImage(named: "buttonImage"), forState: .Normal)
button.addTarget(self, action: "didTouchButton:", forControlEvents:.TouchUpInside)
Swift 3의 우아한 방법 및 이해하기 쉬운 방법:
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
let leftMargin:CGFloat = 40
let imgWidth:CGFloat = 24
let imgHeight:CGFloat = 24
return CGRect(x: leftMargin, y: (contentRect.size.height-imgHeight) * 0.5, width: imgWidth, height: imgHeight)
}
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let leftMargin:CGFloat = 80
let rightMargin:CGFloat = 80
return CGRect(x: leftMargin, y: 0, width: contentRect.size.width-leftMargin-rightMargin, height: contentRect.size.height)
}
override func backgroundRect(forBounds bounds: CGRect) -> CGRect {
let leftMargin:CGFloat = 10
let rightMargin:CGFloat = 10
let topMargin:CGFloat = 10
let bottomMargin:CGFloat = 10
return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}
override func contentRect(forBounds bounds: CGRect) -> CGRect {
let leftMargin:CGFloat = 5
let rightMargin:CGFloat = 5
let topMargin:CGFloat = 5
let bottomMargin:CGFloat = 5
return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin)
}
수직 센터링을 위한 나의 접근 방식:
extension UIButton {
/// Layout image and title with vertical centering.
/// - Parameters:
/// - size: The button size.
/// - imageTopOffset: Top offset for image.
/// - spacing: Distance between image and title.
func verticalAlignmentByCenter(size: CGSize, imageTopOffset: CGFloat, spacing: CGFloat) {
let contentRect = contentRect(forBounds: CGRect(origin: .zero, size: size))
let imageRect = imageRect(forContentRect: contentRect)
let titleRect = titleRect(forContentRect: contentRect)
let imageTop = imageTopOffset - imageRect.origin.y
let imageLeft = contentRect.width/2 - imageRect.width/2
imageEdgeInsets = UIEdgeInsets(top: imageTop, left: imageLeft, bottom: 0, right: 0)
let titleTop = imageTopOffset + spacing + imageRect.height - titleRect.origin.y
let titleLeft = titleRect.origin.x - contentRect.width/2 - titleRect.width/2
titleEdgeInsets = UIEdgeInsets(top: titleTop, left: titleLeft, bottom: 0, right: 0)
}
}
@ravron은 그 대답을 훌륭하게 해냈다.
제 경우 이미지와 제목 사이에 가로 폭을 추가하는 것뿐만 아니라 버튼의 '선행'과 '추적'에 가로 공간을 추가해야 했습니다.
따라서 내부 이미지와 라벨의 intrent Content Size를 사용했습니다.
뷰 자체의 속성만 고려하는 수신 뷰의 원래 크기입니다.
| |
|[LEADING SPACE] [Image] [SPACE BETWEEN IMAGE AND TITLE] Add To [TRAILING SPACE]|
| Favorites |
let leadingTrailingSpace = 10
let horizontalWidthBetweenImageAndTitle = 4
let insetAmount = horizontalWidthBetweenImageAndTitle / CGFloat(2)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -CGFloat(insetAmount), bottom: 0, right: insetAmount);
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: CGFloat(insetAmount), bottom: 0, right: -insetAmount);
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: CGFloat(insetAmount), bottom: 0, right: insetAmount);
let buttonWidth =
(button.titleLabel?.intrinsicContentSize.width ?? 0) +
(button.imageView?.intrinsicContentSize.width ?? 0)
+ insetAmount
+ leadingTrailingSpace
button.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true
다른 상황의 이유로 버튼 구성을 사용하지 않는 경우.이하의 기능을 실장할 수 있습니다.
버튼에 이미지가 설정되어 있는 경우.imageView 버튼은 원하는 방법으로 사용할 수 있습니다.위치 이미지 버튼을 변경합니다.Fallowing Function(하강 기능)은 입력된 값을 버튼의 선행 앵커로부터의 오프셋으로 구현합니다.
private func leftPadding(value: CGFloat, button: UIButton) {
button.imageView?.translatesAutoresizingMaskIntoConstraints = false
button.imageView?.leadingAnchor.constraint(equalTo: button.leadingAnchor, constant: value).isActive = true
button.imageView?.centerYAnchor.constraint(equalTo: button.centerYAnchor).isActive = true
}
iOS 15 이상:
var config = UIButton.Configuration.plain() // depends on the button you want
config.image = UIImage(named: "view_all") // set the image
config.imagePadding = 5 // add the insets for the image
button.configuration = config // assign the config to the button
출처 : https://developer.apple.com/documentation/uikit/uibutton/configuration
솔루션의 신속한 4.2 버전은 다음과 같습니다.
let spacing: CGFloat = 10 // the amount of spacing to appear between image and title
self.button?.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: spacing)
self.button?.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing, bottom: 0, right: 0)
언급URL : https://stackoverflow.com/questions/4564621/aligning-text-and-image-on-uibutton-with-imageedgeinsets-and-titleedgeinsets
'programing' 카테고리의 다른 글
| POI에서 Excel 워크시트 복사 (0) | 2023.04.20 |
|---|---|
| UI 스레드의 디스패처를 입수하려면 어떻게 해야 합니까? (0) | 2023.04.20 |
| KeyVaultErrorException:작업에서 잘못된 상태 코드 '금지됨'을 반환했습니다. (0) | 2023.04.20 |
| 텍스트 길이를 기준으로 UILabel 너비를 계산하는 방법은 무엇입니까? (0) | 2023.04.20 |
| SQL Server의 모든 테이블을 검색하여 문자열 찾기 (0) | 2023.04.20 |


![XCode 13 - [Attribute]탭](https://i.stack.imgur.com/8SX2L.png)

