자동 레이아웃-UIButton의 고유 크기에는 제목 삽입이 포함되지 않습니다


196

자동 레이아웃을 사용하여 UIButton을 정렬하면 크기가 내용에 맞게 잘 조정됩니다.

이미지를로 설정하면 button.image고유 크기가 다시 설명됩니다.

그러나 titleEdgeInsets버튼을 조정하면 레이아웃이이를 설명하지 않고 대신 버튼 제목을 자릅니다.

버튼의 고유 너비가 삽입을 설명하도록하려면 어떻게해야합니까?

여기에 이미지 설명을 입력하십시오

편집하다:

나는 다음을 사용하고 있습니다 :

[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

목표는 이미지와 텍스트를 약간 분리하는 것입니다.


3
이것을 레이더로 제출 했습니까? 확실히 UIButton의 고유 크기 계산에서 버그로 보입니다.
Ryan Poolos 2014

1
레이더를 제출할 준비가되었지만 실제로 예상되는 동작 인 것 같습니다. UIButton의 * EdgeInsets 속성 에 설명되어 있습니다. "지정된 삽입은 해당 사각형의 크기를 단추 텍스트에 맞게 조정 한 후 제목 사각형에 적용됩니다. 따라서 양의 삽입 값은 실제로 제목 텍스트를 클리핑 할 수 있습니다. [...] 버튼은이 속성을 사용하여 intrinsicContentSize 및 sizeThatFits :를 결정하지 않습니다. "
기 illa 알기 스

7
@GuillaumeAlgis 나는 이것이 언급 된 행동이지만 자동 레이아웃을 사용할 때 일어날 것으로 예상되는 것은 아니라고 주장합니다 . 버그를 신고했으며 다른 사람들도 버그를 제기하도록 권장합니다.
memmons

여기서 레이더 버그에 연결할 수 있다면 클릭하고 +1 할 수 있습니까?
gprasant

1
에서 titleEdgeInset문서 : The insets you specify are applied to the title rectangle after that rectangle has been sized to fit the button’s text. Thus, positive inset values may actually clip the title text. 그래서는 삽입을 추가하여 확실히 텍스트를 클립 버튼을 강요
마르코 파 팔라도

답변:


192

메서드를 재정의하거나 임의의 너비 제약 조건을 설정하지 않고도이 문제를 해결할 수 있습니다. 다음과 같이 Interface Builder에서 모든 작업을 수행 할 수 있습니다.

  • 내장 버튼 너비는 제목 너비 + 아이콘 너비 + 왼쪽 및 오른쪽 내용 가장자리 삽입 에서 파생됩니다 .

  • 버튼에 이미지와 텍스트가 모두 있으면 버튼이 사이에 패딩없이 그룹으로 중앙에 배치됩니다.

  • 왼쪽 내용 삽입을 추가하면 텍스트 + 아이콘이 아니라 텍스트를 기준으로 계산됩니다.

  • 음수의 왼쪽 이미지 삽입을 설정하면 이미지가 왼쪽으로 당겨 지지만 전체 버튼 너비에는 영향을 미치지 않습니다.

  • 음수의 왼쪽 이미지 삽입을 설정하면 실제 레이아웃은 해당 값의 절반을 사용합니다. 따라서 -20 포인트 왼쪽 삽입을 얻으려면 Interface Builder에서 -40 포인트 왼쪽 삽입 값을 사용해야합니다.

따라서 원하는 왼쪽 삽입물 아이콘과 텍스트 사이의 안쪽 여백 을위한 공간을 만들기에 충분한 왼쪽 내용 삽입물을 제공 한 다음 아이콘과 텍스트 사이에서 원하는 간격을 두 배로 늘려서 아이콘을 왼쪽으로 이동하십시오. 결과는 동일한 왼쪽 및 오른쪽 내용 삽입이있는 버튼과 그룹 사이에 특정 양의 패딩이있는 그룹으로 중앙에 위치한 텍스트 및 아이콘 쌍입니다.

일부 예제 값 :

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)

실제 레이아웃이 음의 왼쪽 삽입 값의 절반을 사용하는 이유는 무엇입니까 ?? 나는 같은 문제가 발생했습니다!
Tony Lin

1
해결 방법이 있다는 것이 좋지만, 이것이 이상한 행동을 정당화하는 데 사용되지 않기를 바랍니다 UIButton.
funct7

205

음수와 양수 제목 및 내용 삽입의 조합을 사용하여 Interface Builder에서 코드를 작성하지 않고도 작동하도록 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

업데이트 : Xcode 7에는 ( Right삽입) 필드 에 음수 값을 입력 할 수없는 버그가 있지만 그 옆에있는 스테퍼 컨트롤을 사용하여 값을 줄일 수 있습니다. (감사합니다 스튜어트)

이렇게하면 이미지와 제목 사이에 8pt의 간격이 추가되고 버튼의 고유 너비가 같은 양만큼 증가합니다. 이처럼 :

여기에 이미지 설명을 입력하십시오


2
자동 레이아웃으로 버튼 너비를 늘리기 위해 contentEdgeInsets (버그가 아님)를 사용하고 있습니다. 라벨을 오른쪽의 빈 공간으로 옮깁니다. 제목 가장자리 삽입 버그를 해결하는 영리한 방법.
ugur

7
이 트릭은 더 이상 작동하지 않습니다. 인터페이스 빌더는 더 이상 Right필드 에서 음수 값을 허용하지 않습니다 .
Joris Mans

7
@JorisMans 음수 값을 입력 할 수는 없지만 텍스트 필드 오른쪽의 스테퍼 컨트롤을 사용하여 필요한 음수 값으로 단계적으로 내려 가서 나에게 도움이되었습니다.
스튜어트

3
이것이 첫 번째 대답이어야합니다. 왜 여기에 있습니까? 나는 ...이를 발견하기 전에 5 다른 시도했습니다
주님 Zsolt에게

2
UIButton에서 텍스트를 가운데에 배치하기 위해 컨텐츠 오른쪽 16을 삽입했습니다
coolcool1994

96

intrinsicContentSizeUIView 에서 메소드를 대체하지 않는 이유는 무엇 입니까? 예를 들면 다음과 같습니다.

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
                      s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}

그러면 자동 레이아웃 시스템에 버튼의 크기를 늘려 삽입을 허용하고 전체 텍스트를 표시해야한다고 알려야합니다. 나는 내 컴퓨터가 아니므로 이것을 테스트하지 않았습니다.


1
내가 아는 한 버튼을 재정의해서는 안됩니다. 문제는 모든 버튼 유형이 다른 서브 클래스에 의해 구현된다는 것입니다.
Sulthan

2
intrinsicContentSizeUIButton이 아닌 UIView의 메소드이므로 UIButton 메소드를 망칠 필요가 없습니다. 애플은 이것이 문제라고 생각하지 않는다. "이 방법을 재정의하면 커스텀 뷰가 컨텐츠에 기반한 크기를 레이아웃 시스템에 전달할 수있다." 그리고 OP는 다른 버튼에 대해서만 아무 말도하지 않았습니다.
Maarten

1
이것은 확실히 작동하며 내가 함께 해결 한 솔루션입니다. intrinsicContentSize실제로 UIView의 메소드이고 UIButton은 UIView의 서브 클래스이므로이 메소드를 대체 할 수 있습니다. 애플의 문서에는 당신이해서는 안된다는 말이 없습니다. Maarten의 재정의 된 메소드를 사용하여 UIButton 서브 클래스를 만들고 Interface Builder에서 UIButton을 YourUIButtonSubclass 유형으로 변경하면 완벽하게 작동합니다.
n8tr

37
나에게 보인다 intrinsicContentSize 있는 UIButton이 titleEdgeInsets에 추가해야합니다, 나는 애플과 버그를 제기 할거야.
progrmr

6
imageEdgeInsets에 대해서도 동의합니다.
Ricardo Sanchez-Saez

87

삽입 설정 방법을 지정하지 않았으므로 동일한 효과를 볼 수 있기 때문에 titleEdgeInsets를 사용하고 있다고 생각합니다. contentEdgeInsets를 대신 사용하면 제대로 작동합니다.

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}

실제로 titleEdgeInsets를 사용하고 있습니다. 버튼 가장자리의 이미지가 아닌 이미지와 제목의 거리를 두어야합니다. 어쩌면 패딩이있는 이미지를 사용해야합니까? 그래도 해키 보인다.
벤 패커드

이것은 자동 레이아웃과 함께 완벽하게 작동합니다. 감사합니다!
Cal S

3
이것은 intrinsicContentSize를 건드리지 않고 원하는 것을 정확하게 수행하기 때문에 더 나은 솔루션입니다.
RyJ

28
이미지를 사용하고 이미지와 타이틀 사이의 삽입을 조정해야 할 때 질문에 대답하지 않습니다!
브로디 로버트슨

23

그리고 Swift가 이것을 위해 일했습니다 :

extension UIButton {
    override open var intrinsicContentSize: CGSize {
        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}

사랑 U 스위프트


1
Apple 문서는 내장 크기가 계산에 titleEdgeInsets를 포함하지 않는다고 명시 적으로 명시하므로 확장을 사용하면 Apple의 기대뿐만 아니라 읽는 다른 모든 개발자에게도 위반되므로 명시 적으로 언급하기 때문에이 경우 서브 클래스 화하는 것이 좋습니다. 문서.
사이렌

18

이 스레드는 조금 낡았지만 방금 나에게 부딪 쳤고 부정적인 삽입을 사용하여 해결할 수있었습니다. 예를 들어 원하는 패딩 값을 여기에 바꿉니다.

UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
                                            -desiredRightPadding,
                                            -desiredTopPadding,
                                            -desiredLeftPadding);

올바른 자동 레이아웃 제약 조건과 함께 이미지와 텍스트를 포함하는 자동 크기 조정 버튼이 생깁니다! desiredLeftPadding10 으로 설정하면 아래와 같습니다 .

이미지와 짧은 텍스트가있는 버튼

이미지와 긴 텍스트가있는 버튼

버튼의 실제 프레임이 레이블을 포함하지 않는 것을 볼 수 있습니다 (라벨이 경계 바깥쪽으로 오른쪽으로 10 포인트 이동 되었기 때문에).


1
이것은 서브 클래스가 필요하지 않기 때문에 내가 사용한 솔루션입니다. 윌하지 작업 당신의 단추 배경을 가지고 있지만, 일반적으로 아이폰 OS 7에 문제가 아니라면
호세 마누엘 산체스

버튼의 내용 오프셋 (양수 값> = 제목 삽입)도 설정하면 배경 이미지와 함께 작동합니다.
벤 플린

9

대한 스위프트 3 를 기반으로 pegpeg 의 대답 :

extension UIButton {

    override open var intrinsicContentSize: CGSize {

        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)

    }

}

안녕하세요. interfacebuilder에서 사용자 정의 확장 버튼을 사용하고 싶습니다. PLZ 도움말
kemdo

6

iOS 9 이상 에서는 위의 모든 기능이 작동하지 않았습니다 .

  • 너비 제한을 추가합니다 (버튼에 텍스트가 없을 때의 최소 너비). 텍스트가 제공되면 버튼의 크기가 자동 조정됩니다.
  • 관계를보다 크거나 같게 설정

여기에 이미지 설명을 입력하십시오

이제 버튼 주위에 테두리를 추가하려면 다음 방법을 사용하십시오.

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);

왜 안돼? 내용에 따라 자동으로 조정되므로 최소 너비 만 설정하면됩니다 (표시되는 텍스트보다 작을 수 있음)
Oritm

최소 너비를 정의하기 때문입니다. 자동 레이아웃의 전체 아이디어는 명시 적 (최소) 너비를 설정하지 않고 완료된 것입니다.
Joris Mans

너비가 아니라 원하는 경우 너비를 1로 설정할 수 있지만 자동 레이아웃은 너비가 같거나 클 수 있음을 알아야합니다 . 나는 내 대답을 업데이 트
Oritm

너비 제한이 전혀 필요하지 않습니다. contentEdgeInset이 핵심이며 자동 레이아웃은 본질적인 콘텐츠 크기에 사용합니다.
Chris Conover

5

UIButton 아이콘과 레이블 사이에 5pt 간격을 추가하고 싶었습니다. 이것이 내가 달성 한 방법입니다.

UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);

contentEdgeInsets, titleEdgeInsets 및 imageEdgeInsets가 서로 관련되는 방식에는 각 삽입물에서 약간의 여유가 필요합니다. 따라서 제목 왼쪽에 삽입물을 추가하면 오른쪽에 음수 삽입물을 추가하고 내용 오른쪽에 양수 삽입물을 통해 공간을 더 확보해야합니다.

제목 삽입물의 이동과 일치하도록 올바른 내용 삽입을 추가하면 텍스트가 단추의 경계를 벗어나지 않습니다.


3

이 옵션은 인터페이스 빌더에서도 사용할 수 있습니다. 삽입을 참조하십시오. 좌우를 3으로 설정했습니다. 매력처럼 작동합니다.

인터페이스 빌더 스크린 샷


1
예, 이 답변이 설명하는 것처럼 작동하는 이유 는 Edge : Title 또는 Edge : Image 대신 Edge : Content here를 조정하기 때문 입니다.
smileyborg

1

내가 사용하는 솔루션은 버튼에 너비 제한을 추가하는 것입니다. 그런 다음 초기화 어딘가에서 텍스트가 설정된 후 다음과 같이 너비 제약 조건을 업데이트하십시오.

self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;

어디에 8은 당신의 삽입물입니다.


buttonWidthConstraint 란 무엇입니까?
Alexey Golikov


1
버튼의 고유 컨텐츠 크기가 변경되면 constant제약 조건을 새로운 값 으로 수동으로 업데이트해야하고 버튼의 고유 컨텐츠 크기가 변경되는시기를 알아야하기 때문에 이는 훌륭한 솔루션이 아닙니다. 버튼을 서브 클래스 화하지 않고.
smileyborg

Ayup. 이 방법을 더 이상 사용하지 않습니다. 다운 투표에 합당하지만 ¯_ (ツ) _ / ¯
Bob Spryn이

setNeedsUpdateConstraints버튼 제목 또는 이미지를 업데이트 한 후 "수동으로" 호출 할 수 있습니다. 그런 다음 거기에서 상수 를 재정의 updateConstraints하고 다시 계산할 수 있습니다 buttonWidthConstraint. 이것이 반드시 최선의 접근 방법은 아니지만 나에게 충분히 효과적입니다. YMMV;)
올리비에

1

sizeToFit ()를 호출하면 contentEdgeInset이 적용됩니다.

extension UIButton {

   open override func draw(_ rect: CGRect) { 
       self.contentEdgeInsets = UIEdgeInsets(top: 10, left: 40, bottom: 10, right: 40)
       self.sizeToFit()
   }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.