티스토리 뷰
안녕하세요 :) 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%)
이렇게 퍼센트를;;;; 넣을 수 있다.
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이란것도 있나보다!!
허허
참고
'공부' 카테고리의 다른 글
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 |
- fastlane
- FLUTTER
- swift 공부
- 제이슨 파싱
- 스위프트 문법
- 피아노
- Combine
- WidgetKit
- SwiftUI
- 스위프트
- Git
- Swift
- np-hard
- github
- WWDC
- swift3
- Xcode
- ios 13
- swift array
- IOS
- iOS delegate
- actor
- 회고
- swift tutorial
- swift delegate
- swift sort
- np-complete
- WKWebView
- Accessibility
- UIBezierPath
- Total
- Today
- Yesterday