UILabel에 공간 / 패딩 추가


187

나는이 UILabel내가 상단과 하단에 공간을 추가 할 위치. 미니 먼 높이가 제한되어 있으므로 다음과 같이 수정했습니다.

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

편집 : 이렇게하려면 내가 사용했습니다 :

  override func drawTextInRect(rect: CGRect) {
        var insets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 10.0, bottom: 0.0, right: 10.0)
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))

    } 

그러나 두 줄 이상을 쓰면 문제가 동일하기 때문에 다른 방법을 찾아야합니다.

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



우리는 마침내 모든 동적 사례에서 다시 레이아웃하거나 다른 문제가 없어도 UILabel을 완벽하게 대체 할 수있는 방법으로이를 올바르게 수행하는 방법을 정확히 알아 냈습니다. 휴. stackoverflow.com/a/58876988/294884
Fattie

답변:


122

UILabel을 사용하여 하위 클래스를 지정하지 않으려면 Mundi가 명확한 솔루션을 제공했습니다.

또는 UILabel을 UIView로 랩핑하지 않으려는 경우 UITextView를 사용하여 UIEdgeInsets (패딩) 또는 서브 클래스 UILabel을 사용하여 UIEdgeInsets를 지원할 수 있습니다.

UITextView를 사용하면 삽입물 (OBJ-C) 만 제공하면됩니다.

textView.textContainerInset = UIEdgeInsetsMake(10, 0, 10, 0);

대안으로, UILabel 을 서브 클래 싱 하는 경우이 접근법의 예는 drawTextInRect 메소드
(OBJ-C)를 대체하는 것입니다.

- (void)drawTextInRect:(CGRect)uiLabelRect {
    UIEdgeInsets myLabelInsets = {10, 0, 10, 0};
    [super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, myLabelInsets)];
}

TOP, LEFT, BOTTOM 및 RIGHT에 대한 삽입 변수를 새 하위 클래스 UILabel에 추가로 제공 할 수 있습니다.

예제 코드는 다음과 같습니다.

.h (OBJ-C)

float topInset, leftInset,bottomInset, rightInset;

.m (OBJ-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, UIEdgeInsetsMake(topInset,leftInset,bottomInset,rightInset))];
}

편집 # 1 :

내가 본 것에서 UILabel의 intrinsicContentSize를 서브 클래스 화 할 때 재정의해야합니다.

따라서 다음 과 같이 intrinsicContentSize 를 재정의해야합니다 .

- (CGSize) intrinsicContentSize {
    CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
    intrinsicSuperViewContentSize.height += topInset + bottomInset ;
    intrinsicSuperViewContentSize.width += leftInset + rightInset ;
    return intrinsicSuperViewContentSize ;
}

다음 방법을 추가하여 개별적으로 편집하는 대신 삽입물을 편집하십시오.

- (void) setContentEdgeInsets:(UIEdgeInsets)edgeInsets {
    topInset = edgeInsets.top;
    leftInset = edgeInsets.left;
    rightInset = edgeInsets.right; 
    bottomInset = edgeInsets.bottom;
    [self invalidateIntrinsicContentSize] ;
}

UILabel의 크기를 업데이트하여 가장자리 삽입과 일치시키고 참조 한 여러 줄의 필요성을 충족시킵니다.

편집 # 2

조금 검색 한 후 IPInsetLabel 로이 요점 을 발견했습니다 . 이러한 솔루션 중 아무것도 작동하지 않으면 시도해 볼 수 있습니다.

편집 # 3

이 문제에 대해 비슷한 질문 (중복)이있었습니다.
사용 가능한 솔루션의 전체 목록은 다음 답변을 참조하십시오. UILabel 텍스트 여백


죄송하지만, 이미 사용했습니다 :`override func drawTextInRect (rect : CGRect) {var insets : UIEdgeInsets = UIEdgeInsets (top : 0.0, left : 10.0, bottom : 0.0, right : 10.0) super.drawTextInRect (UIEdgeInsetsInsetRect (rect, insets) ))}`결과가 동일하기 때문에 작동하지 않습니다. 동적으로 작동하지 않습니다.
Annachiara

UILabel 대신 UITextView를 사용해 보셨습니까? 아니면 정말 UILabel을 사용해야합니까?
nunofmendes

@Annachiara 내가 만든 편집을 확인하십시오. 작동하는지 확인하십시오.
nunofmendes

확인. 텍스트 뷰가 작동 했습니까? Swift로 작성하지 않아서 죄송하지만 여전히 Obj-C 모드입니다. 이 코드의 목표는 결론에 도달하는 데 도움이되는 것이 었습니다. 희망 했어.
nunofmendes

1
TextView 및 일부 스토리 보드 설정 및 self.textview.textContainerInset = UIEdgeInsetsMake (0, 10, 10, 10); 마침내 작동합니다! 감사 !
Annachiara

208

나는 Swift 4.2 에서 그것을 사용해 보았습니다 .

@IBDesignable class PaddingLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 5.0
    @IBInspectable var bottomInset: CGFloat = 5.0
    @IBInspectable var leftInset: CGFloat = 7.0
    @IBInspectable var rightInset: CGFloat = 7.0

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: rect.inset(by: insets))
    }

    override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + leftInset + rightInset,
                      height: size.height + topInset + bottomInset)
    }   

    override var bounds: CGRect {
        didSet {
            // ensures this works within stack views if multi-line
            preferredMaxLayoutWidth = bounds.width - (leftInset + rightInset)
        }
    } 
}

또는 여기에서 CocoaPods를 사용할 수 있습니다 https://github.com/levantAJ/PaddingLabel

pod 'PaddingLabel', '1.2'

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


6
uilabel 너비가 변경되지 않아 텍스트가 "..."가됩니다.
neobie

1
@Tai Le, 공유해 주셔서 감사합니다, 나는 그것을 테이블 뷰에서 사용했습니다. 왜 텍스트가 잘리는 지 모르겠습니다. 학생, 스튜 덴된다
vishwa.deepak

1
@ 팀 어쩌면 당신은 사용을 의미 한min
ielyamani

4
여기 경고의 한마디. 이 솔루션을 UILabel 하위 클래스에서 사용하고 있습니다. 여러 줄 모드에서 이러한 레이블을 사용하는 경우 세로 UIStackView에서 문제가 있습니다. 때로는 레이블의 크기를 올바르게 지정하지 않고 레이블이 텍스트를 감싸는 것처럼 보이므로 문자열 끝에서 한두 단어가 누락됩니다. 지금은 해결책이 없습니다. 내가 만들면 여기에 쓰겠습니다. 나는이 문제가 여기에 있음을 증명하기 전에이 문제를 파고 들었습니다.
Darren Black

1
이러한 상황에서 작동하게하려면 "setBounds"를 재정의하고 self.preferredMaxLayoutWidth를 경계 너비로 빼고 왼쪽 및 오른쪽 삽입을 빼십시오
Arnaud Barisain-Monrose

82

스위프트 3

import UIKit

class PaddingLabel: UILabel {

   @IBInspectable var topInset: CGFloat = 5.0
   @IBInspectable var bottomInset: CGFloat = 5.0
   @IBInspectable var leftInset: CGFloat = 5.0
   @IBInspectable var rightInset: CGFloat = 5.0

   override func drawText(in rect: CGRect) {
      let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
      super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
   }

   override var intrinsicContentSize: CGSize {
      get {
         var contentSize = super.intrinsicContentSize
         contentSize.height += topInset + bottomInset
         contentSize.width += leftInset + rightInset
         return contentSize
      }
   }
}

약간의 주석 :이 클래스를 ID 관리자 (사용자 정의 클래스)에서 레이블로 설정하고 속성 관리자에서 레이블 패딩이라는 새로운 속성을 사용하십시오. 5 개 이하의 패딩도 효과가 없습니다
iman kazemayni

3
레이블이 높이를 계산할 때 0으로 채워지기 때문에 다중 행 레이블에서는 항상 올바르게 작동하지 않습니다.
fhucho

76

IB에서 올바르게 수행 할 수 있습니다.

  1. 텍스트를 속성으로 변경

표시된 텍스트

  1. "..."가있는 드롭 다운 목록으로 이동

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

  1. 줄, 단락 및 텍스트에 대한 패딩 속성이 첫 줄 들여 쓰기 또는 원하는 항목에 표시됩니다

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

  1. 결과를 확인

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


1
스토리 보드에서 텍스트가 변경되었지만 앱을 실행하면 볼 수 있습니다. 텍스트에 변경 사항이 표시되지 않습니다 ... T_T .. 내 레이블이 사용자 정의 셀 안에 있습니다. 문제가 있습니까?
A. Trejo

1
@ A.Trejo 런타임시 사용자 정의 셀이 레이블 특성을 설정했을 수 있습니다.
Pierre-Yves Guillemet

1
스토리 보드에는 변경 사항이 표시 될 수 있지만 앱을 실행할 때 변경 사항이 없습니다.
Rhenz

4
프로그래밍 방식으로 텍스트를 설정할 때는 적용 할 수 없습니다.
Nij

1
이것은 답이 아닙니다. 모든 방향의 패딩이 아닌 첫 번째 줄 들여 쓰기 만 제어 할 수 있습니다.
rommex

49

스위프트 4

사용하기 쉬운 솔루션으로 프로젝트의 모든 UILabel 자식에 사용할 수 있습니다.

예:

let label = UILabel()
    label.<Do something>
    label.padding = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 0)

UILabel 확장

import UIKit

extension UILabel {
    private struct AssociatedKeys {
        static var padding = UIEdgeInsets()
    }

    public var padding: UIEdgeInsets? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.padding) as? UIEdgeInsets
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(self, &AssociatedKeys.padding, newValue as UIEdgeInsets?, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }

    override open func draw(_ rect: CGRect) {
        if let insets = padding {
            self.drawText(in: rect.inset(by: insets))
        } else {
            self.drawText(in: rect)
        }
    }

    override open var intrinsicContentSize: CGSize {
        guard let text = self.text else { return super.intrinsicContentSize }

        var contentSize = super.intrinsicContentSize
        var textWidth: CGFloat = frame.size.width
        var insetsHeight: CGFloat = 0.0
        var insetsWidth: CGFloat = 0.0

        if let insets = padding {
            insetsWidth += insets.left + insets.right
            insetsHeight += insets.top + insets.bottom
            textWidth -= insetsWidth
        }

        let newSize = text.boundingRect(with: CGSize(width: textWidth, height: CGFloat.greatestFiniteMagnitude),
                                        options: NSStringDrawingOptions.usesLineFragmentOrigin,
                                        attributes: [NSAttributedString.Key.font: self.font], context: nil)

        contentSize.height = ceil(newSize.size.height) + insetsHeight
        contentSize.width = ceil(newSize.size.width) + insetsWidth

        return contentSize
    }
}

1
답변을 간단하게 설명하고 코드 만 게시하지 마십시오.
lmiguelvargasf 1

4
확장 프로그램에서 numberOfLines
Antoine Bodart

이것은 훌륭하지만 여러 줄에 문제가 있습니다 .2 줄을 추가하거나 0으로 남겨두면 항상 하나를 표시합니다. 당신은 그것을 해결하는 방법을 알고 있습니까?
Mago Nicolas Palacios

1
@AntoineBodart 당신은 numberOfLines 문제를 해결하기 위해 관리 했습니까?
Mago Nicolas Palacios

@ AntoineBodart, @Mago Nicolas Palacios-해결되었습니다!
iEvgen Podkorytov

47

UIView슈퍼 뷰로 사용하고 자동 레이아웃으로 레이블에 고정 된 여백을 정의하십시오.


1
drawTextInRect 한 줄에만 intrinsicContentSize작동하며 가로 패딩에는 작동하지 않습니다. UIView의 내부 랩 UILabel의 갈 좋은 방법입니다
onmyway133

8
당신이 IB에 있다면, 이제 메뉴 편집기-> 내장->보기를 기억할 때입니다. UILabel을 먼저 선택하십시오. :)
Graham Perks

46

이미 내장 된 UIButton을 사용하기 만하면됩니다. 모든 추가 버튼 기능을 끄고 가장자리 통계를 설정할 수있는 레이블이 있습니다.

let button = UIButton()
button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
button.setTitle("title", for: .normal)
button.tintColor = .white // this will be the textColor
button.isUserInteractionEnabled = false

2
이건 좋은 팁입니다! 확장이 필요하지 않습니다! :-D
Felipe Ferri

2
isUserInteractionEnabled = false사용하지 않도록 설정 하면 편리합니다.
mxcl

유용한 팁 ... 확장 프로그램을 사용하는 것보다는이 작업을 수행하고 싶습니다.
Ross

1
좋은 팁, Interface Builder에서도 가능하다는 큰 장점
Ely

1
서브 클래 싱 등이없는 최상의 솔루션
MeGaPk

16

스토리 보드없이 :

class PaddingLabel: UILabel {

    var topInset: CGFloat
    var bottomInset: CGFloat
    var leftInset: CGFloat
    var rightInset: CGFloat

    required init(withInsets top: CGFloat, _ bottom: CGFloat,_ left: CGFloat,_ right: CGFloat) {
        self.topInset = top
        self.bottomInset = bottom
        self.leftInset = left
        self.rightInset = right
        super.init(frame: CGRect.zero)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override var intrinsicContentSize: CGSize {
        get {
            var contentSize = super.intrinsicContentSize
            contentSize.height += topInset + bottomInset
            contentSize.width += leftInset + rightInset
            return contentSize
        }
    }
}

용법:

let label = PaddingLabel(8, 8, 16, 16)
label.font = .boldSystemFont(ofSize: 16)
label.text = "Hello World"
label.backgroundColor = .black
label.textColor = .white
label.textAlignment = .center
label.layer.cornerRadius = 8
label.clipsToBounds = true
label.sizeToFit()

view.addSubview(label)

결과:


작동하지만 여러 줄을 허용하는 방법을 알고 있습니까? "PaddingLabel (withInsets : 8, 8, 16, 16)"으로 init를 변경하십시오
Camilo Ortegón

16

UILabel완벽한 솔루션 패딩 . 2020 년에 업데이트되었습니다.

수행해야 할 세 가지 가 있음이 밝혀 졌습니다.

1. 새로운 작은 크기로 textRect # forBounds 호출해야 합니다.

2. 새로운 작은 크기로 drawText를 재정의해야합니다.

3. 동적 크기의 셀인 경우 intrinsicContentSize를 조정해야합니다.

아래의 일반적인 예에서 텍스트 단위는 테이블보기, 스택보기 또는 이와 유사한 구성으로 고정 너비 를 제공합니다 . 이 예에서는 60,20,20,24의 패딩을 원합니다.

따라서 "존재하는"intrinsicContentSize를 가져와 실제로 height에 80을 추가합니다 .

반복하려면 ...

엔진에 의해 "지금까지"계산 된 높이를 문자 그대로 "얻고" 그 값을 변경 해야합니다.

그 과정이 혼란 스럽지만 그것이 작동하는 방식입니다. 나에게있어, 애플은 "예비 높이 계산"과 같은 이름의 전화를 공개해야한다.

두 번째로 textRect # forBounds 호출 을 새로운 작은 크기로 사용해야합니다 .

따라서 textRect # forBounds에서 먼저 크기를 작게 한 다음 super 호출합니다.

경보! 당신은 해야한다 슈퍼 호출 ,하지 전에!

이 페이지에 대한 모든 시도와 토론을주의 깊게 조사하면 정확한 문제입니다. 일부 솔루션은 "거의 작동하는 것 같다"고 생각하지만 특정 상황에서는 작동하지 않을 것이라고 누군가가보고합니다. 이것이 바로 정확한 이유입니다. 혼동스럽게도 이전이 아니라 나중에 "슈퍼 콜"을해야합니다.

따라서 super를 "잘못된 순서로"호출하면 일반적으로 작동 하지만 특정 텍스트 길이에는 적용되지 않습니다 .

다음은 "부적절하게 슈퍼를 먼저 수행"하는 정확한 시각적 예입니다.

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

textRect # forBounds의 "super first"패턴으로 수행 되었기 때문에 60,20,20,24 여백이 올바른지 확인하십시오. 그러나 크기 계산은 실제로 잘못되었습니다.

결정된:

이제 textRect # forBounds 엔진 만이 계산을 올바르게 수행하는 방법을 알고 있습니다 .

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

드디어!

이 예제에서 UILabel은 너비가 고정 된 일반적인 상황에서 사용됩니다. 따라서 intrinsicContentSize에서는 원하는 전체 높이를 "추가"해야합니다. (너비에 어떤 식 으로든 "추가"할 필요는 없습니다. 고정되어 있으므로 의미가 없습니다.)

그런 다음 textRect # forBounds에서 자동 레이아웃으로 "지금까지 제안 된"범위를 확보하고 여백 을 다음 textRect # forBounds 엔진을 다시 호출하십시오. 즉, super로 말하면 결과가 나타납니다.

마지막으로 간단하게 drawText에서 동일한 작은 상자에 그릴 수 있습니다.

휴!

let UIEI = UIEdgeInsets(top: 60, left: 20, bottom: 20, right: 24) // as desired

override var intrinsicContentSize:CGSize {
    numberOfLines = 0       // don't forget!
    var s = super.intrinsicContentSize
    s.height = s.height + UIEI.top + UIEI.bottom
    s.width = s.width + UIEI.left + UIEI.right
    return s
}

override func drawText(in rect:CGRect) {
    let r = rect.inset(by: UIEI)
    super.drawText(in: r)
}

override func textRect(forBounds bounds:CGRect,
                           limitedToNumberOfLines n:Int) -> CGRect {
    let b = bounds
    let tr = b.inset(by: UIEI)
    let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
    // that line of code MUST be LAST in this function, NOT first
    return ctr
}

다시 한번. "거의"올바른이 QA 및 기타 QA에 대한 답변은 위의 첫 번째 이미지 ( "슈퍼가 잘못된 위치에 있습니다")에서 문제를 겪 습니다 . intrinsicContentSize에서 크기를 크게 한 다음 textRect # forBounds 에서 먼저 첫 번째 제안 범위를 축소 한 다음 super 호출 해야합니다 .

요약 : textRect # forBounds에서 " 최근 호출 "

그것이 비밀입니다.

무효화, sizeThatFits, needsLayout 또는 기타 강제 호출을 추가로 호출 할 필요가 없으며 추가로 호출 할 필요가 없습니다. 정상적인 자동 레이아웃 인출 사이클에서 올바른 솔루션이 올바르게 작동해야합니다.


팁:

모노 스페이스 글꼴로 작업하는 경우 다음 팁을 참조하십시오 . https://stackoverflow.com/a/59813420/294884


11

스위프트 4+

class EdgeInsetLabel: UILabel {
    var textInsets = UIEdgeInsets.zero {
        didSet { invalidateIntrinsicContentSize() }
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        let invertedInsets = UIEdgeInsets(top: -textInsets.top,
                                          left: -textInsets.left,
                                          bottom: -textInsets.bottom,
                                          right: -textInsets.right)
        return textRect.inset(by: invertedInsets)
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: textInsets))
    } 
}

용법:

let label = EdgeInsetLabel()
label.textInsets = UIEdgeInsets(top: 2, left: 6, bottom: 2, right: 6)

WAIT-경우에 따라 실제로 문제가 발견되었습니다. 이전에는 이것이 가장 정답이었습니다. 아래에 정답을 넣었습니다.
Fattie

나는 문제를 보여주는 답변에 이미지를 포함시켰다
Fattie

9

구현 예제가있는 Swift 3 코드

class UIMarginLabel: UILabel {

    var topInset:       CGFloat = 0
    var rightInset:     CGFloat = 0
    var bottomInset:    CGFloat = 0
    var leftInset:      CGFloat = 0

    override func drawText(in rect: CGRect) {
        let insets: UIEdgeInsets = UIEdgeInsets(top: self.topInset, left: self.leftInset, bottom: self.bottomInset, right: self.rightInset)
        self.setNeedsLayout()
        return super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }
}

class LabelVC: UIViewController {

    //Outlets
    @IBOutlet weak var labelWithMargin: UIMarginLabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        //Label settings.
        labelWithMargin.leftInset = 10
        view.layoutIfNeeded()
    }
}

스토리 보드 레이블 객체에 클래스 이름 UIMarginLabel을 추가하는 것을 잊지 마십시오. 행복한 코딩!


8

스위프트 4.2 (엑스 코드 10 베타 6) "UIEdgeInsetsInsetRect는"사용되지. 또한 클래스를 더 유용하게 만들기 위해 공개적으로 선언했습니다.

public class UIPaddedLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 5.0
    @IBInspectable var bottomInset: CGFloat = 5.0
    @IBInspectable var leftInset: CGFloat = 7.0
    @IBInspectable var rightInset: CGFloat = 7.0

    public override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: rect.inset(by: insets))
    }

    public override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + leftInset + rightInset,
                      height: size.height + topInset + bottomInset)
    }

    public override func sizeToFit() {
        super.sizeThatFits(intrinsicContentSize)
    }
}

잘 작동한다. 그러나 CollectionViewCell 내에서 사용하려고 시도하고 재사용 후 크기가 조정되지 않습니다 (sizeToFit 및 layoutIfNeeded 이후의 이벤트). 크기를 조정하는 방법이 있습니까?
Bogy

1
재사용 가능한 뷰로 작동하도록 sizeToFit ()을 업데이트했습니다
Bogy

sizeToFit()"인스턴스 메서드를 재정의하는 방법은 해당 엔 클로징 유형만큼 액세스 가능해야합니다."
psyFi

7

나는 받아 들인 대답을 조금 편집했습니다. 문제가 있습니다 leftInsetrightInset텍스트의 일부가 사라집니다 증가는, B / 라벨의 폭이 좁아되지만 높이가 그림으로 증가하지 않는 C :

고유 내용 크기가 잘못된 패딩 레이블

이 문제를 해결하려면 다음과 같이 텍스트 높이를 다시 계산해야합니다.

@IBDesignable class PaddingLabel: UILabel {

  @IBInspectable var topInset: CGFloat = 20.0
  @IBInspectable var bottomInset: CGFloat = 20.0
  @IBInspectable var leftInset: CGFloat = 20.0
  @IBInspectable var rightInset: CGFloat = 20.0

  override func drawTextInRect(rect: CGRect) {
    let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
    super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
  }

  override func intrinsicContentSize() -> CGSize {
    var intrinsicSuperViewContentSize = super.intrinsicContentSize()

    let textWidth = frame.size.width - (self.leftInset + self.rightInset)
    let newSize = self.text!.boundingRectWithSize(CGSizeMake(textWidth, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil)
    intrinsicSuperViewContentSize.height = ceil(newSize.size.height) + self.topInset + self.bottomInset

    return intrinsicSuperViewContentSize
  }
}

결과 :

올바른 고유 컨텐츠 크기의 패딩 레이블

저와 같은 상황에있는 사람들을 돕고 싶습니다.


2
Swift 3.0 을 사용하려는 경우 새로운 Apple 언어가 이전 기능 정의를 완전히 위반하므로 기능 이름을 변경해야합니다. 그래서 override func drawTextInRect(rect: CGRect)하게 override func drawText(in rect: CGRect)하고 override func intrinsicContentSize() -> CGSize이된다 override var intrinsicContentSize : CGSize 즐기십시오!
DoK

불행히도 나는 그것을 작동시키지 않았다. 코드 스위프트 5 override var intrinsicContentSize: CGSize { // .. return intrinsicSuperViewContentSize }
Nazmul Hasan

7

자동 레이아웃을 사용하십시오.

let paddedWidth = myLabel.intrinsicContentSize.width + 2 * padding
myLabel.widthAnchor.constraint(equalToConstant: paddedWidth).isActive = true

끝난.


키를 사용하여 동일한 작업을 수행 할 수도 있습니다.
ShadeToD

감사합니다
마이크 Taverne

7

서브 클래 싱이없는 다른 옵션은 다음과 같습니다.

  1. 라벨 설정 text
  2. sizeToFit()
  3. 패딩을 시뮬레이션하기 위해 레이블 높이를 약간 늘립니다.

    label.text = "someText"
    label.textAlignment = .center    
    label.sizeToFit()  
    label.frame = CGRect( x: label.frame.x, y: label.frame.y,width:  label.frame.width + 20,height: label.frame.height + 8)

놀랍게도,이 모든 난 그냥 여기에 약간의 수정이 필요했다 : label.frame = CGRect( x: label.frame.origin.x - 10, y: label.frame.origin.y - 4, width: label.frame.width + 20,height: label.frame.height + 8)-10과 -4 중앙 집중화
재정 경제부 Ejegi을

6

스위프트 3, iOS10 솔루션 :

open class UIInsetLabel: UILabel {

    open var insets : UIEdgeInsets = UIEdgeInsets() {
        didSet {
            super.invalidateIntrinsicContentSize()
        }
    }

    open override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize
        size.width += insets.left + insets.right
        size.height += insets.top + insets.bottom
        return size
    }

    override open func drawText(in rect: CGRect) {
        return super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }
}

6

스위프트 3에서

가장 쉽고 간단한 방법

class UILabelPadded: UILabel {
     override func drawText(in rect: CGRect) {
     let insets = UIEdgeInsets.init(top: 0, left: 5, bottom: 0, right: 5)
     super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

}

4

서브 클래스 UILabel. (File-New-File- CocoaTouchClass-UILabel의 서브 클래스 만들기).

//  sampleLabel.swift

import UIKit

class sampleLabel: UILabel {

 let topInset = CGFloat(5.0), bottomInset = CGFloat(5.0), leftInset = CGFloat(8.0), rightInset = CGFloat(8.0)

 override func drawTextInRect(rect: CGRect) {

  let insets: UIEdgeInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
  super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))

 }
 override func intrinsicContentSize() -> CGSize {
  var intrinsicSuperViewContentSize = super.intrinsicContentSize()
  intrinsicSuperViewContentSize.height += topInset + bottomInset
  intrinsicSuperViewContentSize.width += leftInset + rightInset
  return intrinsicSuperViewContentSize
 }
}

ViewController에서 :

override func viewDidLoad() {
  super.viewDidLoad()

  let labelName = sampleLabel(frame: CGRectMake(0, 100, 300, 25))
  labelName.text = "Sample Label"
  labelName.backgroundColor =  UIColor.grayColor()

  labelName.textColor = UIColor.redColor()
  labelName.shadowColor = UIColor.blackColor()
  labelName.font = UIFont(name: "HelveticaNeue", size: CGFloat(22))
  self.view.addSubview(labelName)
 }

또는 스토리 보드의 사용자 정의 UILabel 클래스를 레이블의 클래스로 연관시킵니다.


하드 코딩 된 값을 클래스 속성으로 변경하면 이미이 코드를 사용하고 있습니다.
Juan Boero

@ Juan : drawTextInRect는 UILabel의 기본 클래스 속성으로, 코드를 사용하여 재정의 할 수 없습니다. UILabel을 서브 클래 싱하고 필요한 프레임 변경을 추가하는 가장 좋은 방법입니다. 어쨌든 상속 기능으로서 편리합니다.
AG

이것은 정확하지만 Swift 3부터는 intrinsicContentSize가 함수가 아니라 속성이므로 "func intrinsicContentSize 재정의"대신 "var intrinsicContentSize : CGFloat {}"재정의해야합니다.
joey

4

다른 답변과 마찬가지로 버그를 수정하십시오. label.width자동 레이아웃으로 제어 하면 텍스트가 잘리는 경우가 있습니다.

@IBDesignable
class InsetLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 4.0
    @IBInspectable var leftInset: CGFloat = 4.0
    @IBInspectable var bottomInset: CGFloat = 4.0
    @IBInspectable var rightInset: CGFloat = 4.0

    var insets: UIEdgeInsets {
        get {
            return UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        }
        set {
            topInset = newValue.top
            leftInset = newValue.left
            bottomInset = newValue.bottom
            rightInset = newValue.right
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var adjSize = super.sizeThatFits(size)
        adjSize.width += leftInset + rightInset
        adjSize.height += topInset + bottomInset
        return adjSize
    }

    override var intrinsicContentSize: CGSize {
        let systemContentSize = super.intrinsicContentSize
        let adjustSize = CGSize(width: systemContentSize.width + leftInset + rightInset, height: systemContentSize.height + topInset +  bottomInset) 
        if adjustSize.width > preferredMaxLayoutWidth && preferredMaxLayoutWidth != 0 {
            let constraintSize = CGSize(width: bounds.width - (leftInset + rightInset), height: .greatestFiniteMagnitude)
            let newSize = super.sizeThatFits(constraintSize)
            return CGSize(width: systemContentSize.width, height: ceil(newSize.height) + topInset + bottomInset)
        } else {
            return adjustSize
        }
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: insets))
    }
}

2

쉬운 패딩 (Swift 3.0, Alvin George 답변) :

  class NewLabel: UILabel {

        override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
                return self.bounds.insetBy(dx: CGFloat(15.0), dy: CGFloat(15.0))
        }

        override func draw(_ rect: CGRect) {
                super.drawText(in: self.bounds.insetBy(dx: CGFloat(5.0), dy: CGFloat(5.0)))
        }

  }

2

문디의 답변에 대한 설명.

즉, 라벨을에 삽입하고 UIView자동 레이아웃을 통해 패딩을 적용합니다. 예:

채워진 UILabel처럼 보입니다.

개요 :

1) UIView( "패널")을 만들고 모양을 설정하십시오.

2) a UILabel를 만들어 패널에 추가하십시오.

3) 패딩을 적용하기 위해 제약 조건을 추가합니다.

4) 패널을 뷰 계층 구조에 추가 한 다음 패널을 배치하십시오.

세부:

1) 패널보기를 작성하십시오.

let panel = UIView()
panel.backgroundColor = .green
panel.layer.cornerRadius = 12

2) 레이블을 작성하고이를 서브 뷰로 패널에 추가하십시오.

let label = UILabel()
panel.addSubview(label)

3) 라벨의 가장자리와 패널 사이에 구속 조건을 추가하십시오. 이렇게하면 패널이 레이블과 거리를 유지하게됩니다. 즉 "패딩"

사설 :이 모든 작업을 직접 수행하는 것은 매우 지루하고 장황하며 오류가 발생하기 쉽습니다. github에서 자동 레이아웃 래퍼를 선택하거나 직접 작성하는 것이 좋습니다.

label.panel.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: panel.topAnchor,
    constant: vPadding).isActive = true
label.bottomAnchor.constraint(equalTo: panel.bottomAnchor,
    constant: -vPadding).isActive = true
label.leadingAnchor.constraint(equalTo: panel.leadingAnchor,
    constant: hPadding).isActive = true
label.trailingAnchor.constraint(equalTo: panel.trailingAnchor,
    constant: -hPadding).isActive = true

label.textAlignment = .center

4) 뷰 계층에 패널을 추가 한 다음 위치 구속 조건을 추가하십시오. 예를 들어 이미지와 같이 tableViewCell의 오른쪽을 포옹합니다.

참고 : 치수 구속 조건이 아닌 위치 구속 조건 만 추가하면됩니다. 자동 레이아웃은 intrinsicContentSize레이블과 이전에 추가 한 구속 조건을 기반으로 레이아웃을 해결합니다 .

hostView.addSubview(panel)
panel.translatesAutoresizingMaskIntoConstraints = false
panel.trailingAnchor.constraint(equalTo: hostView.trailingAnchor,
    constant: -16).isActive = true
panel.centerYAnchor.constraint(equalTo: hostView.centerYAnchor).isActive = true

2

패딩을 적용하는 동안 텍스트 트리밍 문제가 발생하면이 코드를 사용하십시오.

@IBDesignable class PaddingLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 5.0
    @IBInspectable var bottomInset: CGFloat = 5.0
    @IBInspectable var leftInset: CGFloat = 5.0
    @IBInspectable var rightInset: CGFloat = 5.0

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override var intrinsicContentSize: CGSize {
        var intrinsicSuperViewContentSize = super.intrinsicContentSize
        let textWidth = frame.size.width - (self.leftInset + self.rightInset)
        let newSize = self.text!.boundingRect(with: CGSize(textWidth, CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil)
        intrinsicSuperViewContentSize.height = ceil(newSize.size.height) + self.topInset + self.bottomInset
        return intrinsicSuperViewContentSize
    }
}

extension CGSize{
    init(_ width:CGFloat,_ height:CGFloat) {
        self.init(width:width,height:height)
    }
}

게시 해 주셔서 감사합니다. 패딩 + 트리밍에 관한 솔루션을 찾고 있습니다. 귀하의 솔루션이 필요한 label.numberOfLines = 0을 깨는 것 같습니다. 해결 방법이 있습니까?
Don

1

다른 답변과 비슷하지만 패딩을 동적으로 설정하는 func 클래스가 있습니다.

class UILabelExtendedView: UILabel
{
    var topInset: CGFloat = 4.0
    var bottomInset: CGFloat = 4.0
    var leftInset: CGFloat = 8.0
    var rightInset: CGFloat = 8.0

    override func drawText(in rect: CGRect)
    {
        let insets: UIEdgeInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override public var intrinsicContentSize: CGSize
    {
        var contentSize = super.intrinsicContentSize
        contentSize.height += topInset + bottomInset
        contentSize.width += leftInset + rightInset
        return contentSize
    }

    func setPadding(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat){
        self.topInset = top
        self.bottomInset = bottom
        self.leftInset = left
        self.rightInset = right
        let insets: UIEdgeInsets = UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
        super.drawText(in: UIEdgeInsetsInsetRect(self.frame, insets))
    }
}

1

실용적인 해결책 중 하나는 기본 레이블과 동일한 높이와 색상의 빈 레이블을 추가하는 것입니다. 선행 / 트레일 공간을 기본 레이블로 0으로 설정하고 수직 중심을 정렬 한 후 너비를 원하는 여백으로 만듭니다.


1

textRect 주위에 2px 패딩을 추가하려면 다음을 수행하십시오.

let insets = UIEdgeInsets(top: -2, left: -2, bottom: -2, right: -2)
label.frame = UIEdgeInsetsInsetRect(textRect, insets)

textRect 란 무엇입니까? label.frame?
Gustavo Baiocchi Costa

1

스토리 보드에서 @IBInspectable / @IBDesignable UILabel을 원하지 않거나 필요로하지 않는다면 (어쨌든 너무 느리게 렌더링된다고 생각합니다) 4 가지 CGFloat 대신 UIEdgeInsets를 사용하는 것이 더 깨끗합니다.

Swift 4.2의 코드 예 :

class UIPaddedLabel: UILabel {
    var padding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    public override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: padding))
    }

    public override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + padding.left + padding.right,
                      height: size.height + padding.top + padding.bottom)
    }
}

1

목표 -C

IB Designable 내부의 기능을 구현하는 Tai Le 답변을 바탕으로 Objective-C 버전이 있습니다.

이것을 YourLabel.h에 넣으십시오

@interface YourLabel : UILabel

@property IBInspectable CGFloat topInset;
@property IBInspectable CGFloat bottomInset;
@property IBInspectable CGFloat leftInset;
@property IBInspectable CGFloat rightInset;

@end

그리고 이것은 YourLabel.m에 갈 것입니다

IB_DESIGNABLE

@implementation YourLabel

#pragma mark - Super

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.topInset = 0;
        self.bottomInset = 0;
        self.leftInset = 0;
        self.rightInset = 0;
    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect {
    UIEdgeInsets insets = UIEdgeInsetsMake(self.topInset, self.leftInset, self.bottomInset, self.rightInset);
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

- (CGSize)intrinsicContentSize {

    CGSize size = [super intrinsicContentSize];
    return CGSizeMake(size.width + self.leftInset + self.rightInset,
                      size.height + self.topInset + self.bottomInset);
}

@end

그런 다음 XIB 또는 스토리 보드 내부에 클래스를 지정한 후 인터페이스 빌더에서 YourLabel 인세 트를 직접 수정할 수 있습니다. 인세 트의 기본값은 0입니다.


0

쉬운 방법

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.addSubview(makeLabel("my title",x: 0, y: 100, w: 320, h: 30))
    }

    func makeLabel(title:String, x:CGFloat, y:CGFloat, w:CGFloat, h:CGFloat)->UILabel{
        var myLabel : UILabel = UILabel(frame: CGRectMake(x,y,w,h))
        myLabel.textAlignment = NSTextAlignment.Right

        // inser last char to right
        var titlePlus1char = "\(title)1"
        myLabel.text = titlePlus1char
        var titleSize:Int = count(titlePlus1char)-1

        myLabel.textColor = UIColor(red:1.0, green:1.0,blue:1.0,alpha:1.0)
        myLabel.backgroundColor = UIColor(red: 214/255, green: 167/255, blue: 0/255,alpha:1.0)


        // create myMutable String
        var myMutableString = NSMutableAttributedString()

        // create myMutable font
        myMutableString = NSMutableAttributedString(string: titlePlus1char, attributes: [NSFontAttributeName:UIFont(name: "HelveticaNeue", size: 20)!])

        // set margin size
        myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue", size: 10)!, range: NSRange(location: titleSize,length: 1))

        // set last char to alpha 0
        myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red:1.0, green:1.0,blue:1.0,alpha:0), range: NSRange(location: titleSize,length: 1))

        myLabel.attributedText = myMutableString

        return myLabel
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

0

쉬운 패딩 :

import UIKit

    class NewLabel: UILabel {

        override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {

            return CGRectInset(self.bounds, CGFloat(15.0), CGFloat(15.0))
        }

        override func drawRect(rect: CGRect) {

            super.drawTextInRect(CGRectInset(self.bounds,CGFloat(5.0), CGFloat(5.0)))
        }

    }

하단 페이지의 3.0 버전
odemolliens

0

스위프트 4+

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = 10

// Swift 4.2++
label.attributedText = NSAttributedString(string: "Your text", attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle])

// Swift 4.1--
label.attributedText = NSAttributedString(string: "Your text", attributes: [NSAttributedStringKey.paragraphStyle: paragraphStyle])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.