티스토리 뷰

공부

PinLayout 사용해보기

Zedd0202 2021. 4. 21. 15:10
반응형

 

안녕하세요 :) Zedd입니다.

View 레이아웃을 도와주는 프레임워크로는 SnapKit만 알고 있었는데..SnapKit말고도 많더라구요~

그 중 하나인 PinLayout을 간단하게 사용해보려고 합니다.

 

# PinLayout

- Auto layout 없이 Swift View 레이아웃을 구성할 수 있도록 도와주는 프레임워크(Auto layout을 사용하지 않고 수동으로 view를 layout한다.) 

💡 수동으로 layouting하므로 디바이스 회전을 포함한 컨테이너 크기의 변경을 처리하려면 UIView.layoutSubviews() 또는 UIViewController.viewDidLayoutSubviews() 내부에서 레이아웃을 업데이트해야함. 

 

# 성능 

PinLayout은 manual layouting(수동 레이아웃)보다 빠르거나 같으며 Auto layout보다 8~12배 빠르다.

진한 파란색이 PinLayout. 높이가 낮을수록 빠른것. 

 

# 설치

문서 참고

 

# 사용법

SnapKit과 유사하면서도....뭔가 다른 것 같다. (아직 별로 사용은 안해봤지만..)

let label = UILabel()
label.backgroundColor = .systemBlue
self.view.addSubview(label)

기본적으로 addSubview까지는 해야한다.

 

[Edges layout]

label.pin.top(10).bottom(10).left(10).right(10)
or 
label.pin.all(10)

SnapKit이 snp였다면, PinLayout은 pin인듯..

첫번째 줄 처럼 top, bottom, left, right 하나하나 명시해줄수도 있지만, all로도 가능 

위 코드는 

이렇게 나온다. 

기본적으로 top, bottom, left, right는 superview의 edge를 기준으로 한다. (safeArea는 따로 처리해줘야함)

4가지 용법이 있는데, 다 똑같으니 top을 예로 들어보겠다.

1. top(_ offset: CGFloat)

제일 간단한 사용방법. 띄우고싶은 만큼의 offset 값을 그냥 넣으면 된다.

2. top(_ offset: Percent)

label.pin.top(10%).left(10%).right(10%).bottom(10%)

이렇게 퍼센트를;;;; 넣을 수 있다. 

SE 2세대 / 아이패드 12.9

10%씩 떨어져있다고 생각하면 됨. 

3. top()

top(0)과 같다. 

4. top(_ margin: UIEdgeInsets)

UIEdgeInsets.top을 사용하며, safeArea layout에 유용.

label.pin.top(self.view.pin.safeArea.top)

이런식으로 사용가능.

 

[Center]

1. hCenter

vertical center(center.y)

2. vCenter

horizontal center (center.x)

label.pin.left().right().vCenter().height(100)

label.pin.top().bottom().hCenter().width(100)

그 외에도

view.pin.top(20).bottom(20)   // The view has a top margin and a bottom margin of 20 pixels 
view.pin.top().left()         // The view is pinned directly on its parent top and left edge
view.pin.all()                // The view fill completely its parent (horizontally and vertically)
view.pin.all(pin.safeArea)    // The view fill completely its parent safeArea 
view.pin.top(25%).hCenter()   // The view is centered horizontally with a top margin of 25%
view.pin.left(12).vCenter()   // The view is centered vertically
view.pin.start(20).end(20)    // Support right-to-left languages.
view.pin.horizontally(20)     // The view is filling its parent width with a left and right margin.
view.pin.top().horizontally() // The view is pinned at the top edge of its parent and fill it horizontally.

이런식으로 활용 가능. 

 

[Layout multiple edges relative to superview]

View를 오른쪽 상단에 붙히고 싶으면

viewA.pin.top().right().size(100)

이렇게 해야할텐데, 간편한 메소드를 제공해준다. 

viewA.pin.topRight().size(100)

위 그림의 메소드들을 이용하여 리팩토링 해보면..아까 위에서 봤던

label.pin.top(10).bottom(10).left(10).right(10)

이 코드는

label.pin.topLeft(10).bottomRight(10)

와 같다.

 

[Relative Edges layout]

view가 여러개 있다고 할 때, viewA옆에, 위에.. viewB를 놓을 수 있을 것이다.

PinLayout에는 관련 메소드들을 제공하는데,

above(of: UIView) / above(of: [UIView])

below(of: UIView) / below(of: [UIView])

before(of: UIView) / before(of: [UIView])

after(of: UIView) / after(of: [UIView])

left(of: UIView) / left(of: [UIView])

right(of: UIView) / right(of: [UIView])

가 있다.

위 메소드들을 사용하여 view를 배치하면

label1.pin.topLeft().size(100)
label2.pin.top().after(of: label1).size(100)
label3.pin.left().below(of: label1).width(200).height(100)

이런 Layout을 간단하게 만들 수 있다. 

aligned 파라미터도 같이 줄 수 있는데, 

label1.pin.topLeft().size(100)
label2.pin.after(of: label1, aligned: .center).size(50)
label3.pin.below(of: label1, aligned: .right).size(50)

이렇게 하면

이렇게 된다. 

 

[Layout between other views]

view를 이렇게 배치하고 싶다고 할 때, 세번째 Label은 첫번째 Label 뒤에, 두번째 Label 앞에 둘 수 있다.

그러면 세번째 Label에 대한 layout 코드는 

label3.pin.after(of: label1).before(of: label2).height(100)

방금 본 after, before류의 메소드들을 이용하여 배치가 가능하다.

물론 그렇게 해도 되지만 PinLayout은 이 상황에서 바로 사용할 수 있는 메소드들 제공해준다.

horizontallyBetween(:UIView, and: UIView)

verticallyBetween(:UIView, and: UIView)

 

ex. horizontallyBetween

label1.pin.topLeft().size(100)
label2.pin.topRight().size(100)
label3.pin.horizontallyBetween(label1, and: label2).height(100) ✅

이렇게 horizontallyBetween을 사용하여 label3를 1, 2사이에 두도록 하면

똑같이 만들어진다.

horizontallyBetween(:UIView, and: UIView, aligned: VerticalAlign)

verticallyBetween(:UIView, and: UIView, aligned: HorizontalAlign)

aligned 파라미터도 같이 넘길 수 있는데, 

label1.pin.topLeft().size(100)
label2.pin.topRight().size(100)
label3.pin.horizontallyBetween(label1, and: label2, aligned: .center).height(50)

이런식으로 사용 가능하다.

 

# 콘솔 warning

label1.pin.width(100).width(200)

이런 말이 안되는 layout을 배치하려고 하면 

👉 PinLayout Conflict: width(200.0) won't be applied since it value has already been set to 100.
(Layouted view info: Type: UILabel, Frame: x: 0, y: 0, width: 0, height: 0), Superviews: UIView, Debug description: <UILabel: 0x130f13960; frame = (0 0; 0 0); text = '첫번째 Label'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x600002e031b0>>)

이렇게 콘솔에 warning이 뜬다.

Pin.logWarnings 프로퍼티를 통해 이 콘솔 warning을 보여줄지 말지 정할 수 있다.

Debug에서는 기본적으로 True로 들어가있기 때문에 별다른 설정 없이 warning이 잘 나올것이다.

Debug에서도 warning을 안보이게 하고 싶다면

Pin.logWarnings = false ✅
label1.pin.width(100).width(200)

Pin.logWarnings을 false로 주면 된다. 

 

# PinLayout style guide

SnapKit에서는 내 맘대로 썼었는데.. PinLayout은 가이드가 있네

 

1. 항상 동일한 순서로 메소드를 명시해야한다. → 레이이웃을 더 쉽게 이해할 수 있기 때문

PinLayout이 선호하는 순서는 

view.pin. [EDGE | ANCHOR | RELATIVE]. [WIDTH | HEIGHT | SIZE]. [pinEdges ()]. ​​[MARGINS]. [sizeToFit ()]

위와 같음.

이 순서는 PinLayout 내부 로직을 반영한다고 한다.

pinEdges()는 margins전에 적용되고, margins은 sizeToFit()전에 적용된다. 

ex. 

view.pin.top().left(10%).margin(10, 12, 10, 12)
view.pin.left().width(100%).pinEdges().marginHorizontal(12)
view.pin.horizontally().margin(0, 12).sizeToFit(.width)
view.pin.width(100).height(100%)

 

2. Edge역시 항상 같은 순서대로 명시할 것. TOP, BOTTOM, LEFT, RIGHT순서

 view.pin.top().bottom().left(10%).right(10%)

 

3. 레이아웃 라인이 너무 길어지면 line을 분리할 것.

textLabel.pin.below(of: titleLabel)
    .before(of: statusIcon).after(of: accessoryView)
    .above(of: button).marginHorizontal(10)

 

# 사용 후기 

현재 PinLayout 1.7k, SnapKit 17.4k.. star수는 많이 차이나는데, SnapKit보다 강력한 메소드들이 많은 것 같다. 

아직 PinLayout쪽에 안 본 메소드들도 엄청 많은데..FlexLayout이란것도 있나보다!! 

허허 

 

참고 

github.com/layoutBox/PinLayout

반응형

'공부' 카테고리의 다른 글

FlexLayout 사용해보기  (4) 2021.05.02
extension Reactive  (1) 2021.04.28
Carthage 사용해보기  (0) 2021.04.17
Carthage  (0) 2021.04.15
Swift ) Quick / Nimble 간단하게 사용해보기  (0) 2021.04.14