이미지와 텍스트 시작 사이에 약 2-3 픽셀의 공간이 있도록 두 줄의 텍스트 왼쪽에 아이콘을 배치하고 싶습니다. 컨트롤 자체는 가로로 가운데 정렬됩니다 (인터페이스 빌더를 통해 설정).
버튼은 다음과 유사합니다.
| |
|[Image] Add To |
| Favorites |
contentEdgeInset, imageEdgeInsets 및 titleEdgeInsets를 사용 하여이 구성을 시도하고 있습니다. 음수 값은 가장자리를 확장하고 양수 값은 축소하여 중앙에 더 가깝게 이동한다는 것을 알고 있습니다.
나는 시도했다 :
[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를 사용하여 이미지와 텍스트를 가운데에 배치하는 방법은 무엇입니까?
답변
나는 문서에 동의 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 + Position.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];
물론 두 번째 범주 방법을 추가 할 수있는 좋은 방법을 만들고 싶을 것입니다. 이것은 독자에게 연습으로 남겨 둡니다.
답변
이 파티에 조금 늦었지만 추가 할만한 것이 있다고 생각합니다.
Kekoa의 답변은 훌륭하지만 RonLugge가 언급했듯이 버튼을 더 이상 존중하지 않거나 sizeToFit
더 중요하게는 본질적으로 크기가 조정 될 때 버튼이 내용을 클리핑 할 수 있습니다. 이케!
하지만 먼저
내가 믿는 방법에 대한 간략한 설명 imageEdgeInsets
과 titleEdgeInsets
일 :
에 대한 문서imageEdgeInsets
는 부분적으로 다음과 같습니다.
이 속성을 사용하여 버튼 이미지의 유효 그리기 사각형의 크기를 조정하고 위치를 조정할 수 있습니다. 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
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)
}
}
답변
인터페이스 빌더에서. UIButton-> 속성 관리자-> Edge = Title을 선택하고 가장자리 삽입을 수정하십시오
답변
또한 비슷한 것을 만들고 싶다면
당신은 필요
1. 버튼의 수평 및 수직 정렬을
-
필요한 모든 값을 찾고 설정
UIImageEdgeInsets
CGSize 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)
}
}
}
}
답변
이것을 사용하면 많은 문제를 피할 수 있습니다.
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
그러면 모든 콘텐츠가 자동으로 왼쪽에 정렬됩니다 (또는 원하는 위치에)
스위프트 3 :
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;
답변
Xcode 8.0 에서는 insets
크기 관리자 를 변경 하여 간단하게 수행 할 수 있습니다 .
UIButton-> 속성 관리자-> 크기 관리자로 이동하여 내용, 이미지 및 제목 삽입을 수정하십시오.
오른쪽에서 이미지를 변경하려면 Force Right-to-left
속성 관리자에서 시맨틱 속성을 로 변경하면 됩니다.
답변
나는이 파티에도 약간 늦었지만 추가 할 유용한 것이 있다고 생각합니다 : o).
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
새로운 레이아웃 속성을 직접 또는 combinaison에.
@ravron이 설명했듯이 버튼 내용을 올바르게 만들기 위해 최선을 다합니다 (빨간색 테두리로 볼 수 있듯이).
Interface Builder에서도 사용할 수 있습니다.
여기 코드 ( 장점 ) :
@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()
}
}