
⎮ 팀 프로젝트 2일차
앞서 얘기한 바와 같이 공정한 사다리타기를 통해 부여된 임무는
상단 Tap Bar 만들기이다.

예상하고 있는 디자인은 다음과 같다.
⎮ UISegmentedContorller에 대하여
나는 이번 상단 TapBar는 UISegmentedController로 구현하고자 한다.
먼저 segment란, "나뉘다, 분절하다"라는 뜻을 가지고 있는데
이름에서 알 수 있듯, UISegmentedController는 여러 개의 세그먼트로 구성된 수평 컨트롤로,
각 세그먼트는 개별 버튼으로 기능하는 Class다.
https://developer.apple.com/documentation/UIKit/UISegmentedControl
UISegmentedControl | Apple Developer Documentation
A horizontal control that consists of multiple segments, each segment functioning as a discrete button.
developer.apple.com
https://developer.apple.com/design/human-interface-guidelines/segmented-controls
Segmented controls | Apple Developer Documentation
A segmented control is a linear set of two or more segments, each of which functions as a button.
developer.apple.com
공식문서에 보면, 아래와 같은 예시 이미지가 있다.

버튼을 선택하면 강조되게 하거나, 이미지를 추가하거나 Label을 추가하는 등의 기능을 할 수 있는데,
이 SegmentedControll은 어떻게 쓰는걸까?
⎮ UISegmentedContorller 기본 구현
먼저 View의 Background Color를 White로 설정한다.
//override func viewDidLoad()에 작성
view.backgroundColor = .white
그리고 segment에 들어갈 데이터와 함께 segmentControl을 만들어준다.
let segment = UISegmentedControl(items: ["First Page", "Second Page"])
segment의 제약을 추가해준 뒤
segment.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
segment.leadingAnchor.constraint(equalTo: view.leadingAnchor),
segment.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
segment.trailingAnchor.constraint(equalTo: view.trailingAnchor),
segment.heightAnchor.constraint(equalToConstant: 70)
])
이후 view에 segment를 추가해준다.
//override func viewDidLoad()에 추가
view.addSubview(segment)
전체 코드는 다음과 같다.
lass ViewController: UIViewController {
let segment = UISegmentedControl(items: ["First Page", "Second Page"])
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(segment)
segment.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
segment.leadingAnchor.constraint(equalTo: view.leadingAnchor),
segment.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
segment.trailingAnchor.constraint(equalTo: view.trailingAnchor),
segment.heightAnchor.constraint(equalToConstant: 70)
])
}
}
이렇게 하면 일단 기본적인 SegmentedControl은 완성이 된다.


⎮ UISegmentedContor Custom 하기
let segment = UISegmentedControl(items: ["First Page", "Second Page"])
앞서 봤던 이 방식 말고 다른 방식으로도 UISegmentedController를 구현할 수 있다.
let segmentControl: UISegmentedControl = {
let segment = UISegmentedControl()
// segment의 항목 구성
segment.insertSegment(withTitle: "피규어", at: 0, animated: true)
segment.insertSegment(withTitle: "티셔츠", at: 1, animated: true)
segment.insertSegment(withTitle: "키링", at: 2, animated: true)
segment.insertSegment(withTitle: "베개", at: 3, animated: true)
다음과 같이 각각의 Segment를 insert해줄 수 있다.
이후 Segment를 만들었을 떄의 기본 index를 설정해줘야 한다.
// segment의 기본 인덱스 설정
segment.selectedSegmentIndex = 0
segmentedControl에는 선택되었을 때, 기본 상태, 강조 등의 옵션이 있는데
가장 기본적인 선택되었을 때와 기본 상태에 대한 텍스트와 TintColor를 별도로 설정해줄 수 있다.
// selected segment의 font 세팅
segment.setTitleTextAttributes([
NSAttributedString.Key.foregroundColor: UIColor(red: 250/255, green: 67/255, blue: 89/255, alpha: 1.0),
NSAttributedString.Key.font: UIFont(name: "GmarketSansBold", size: 16) ?? UIFont.systemFont(ofSize: 16)
], for: .selected)
// non-selected segment의 font 세팅
segment.setTitleTextAttributes([
NSAttributedString.Key.foregroundColor: UIColor.gray,
NSAttributedString.Key.font: UIFont(name: "GmarketSansBold", size: 16) ?? UIFont.systemFont(ofSize: 16)
], for: .normal)

기본적인 SegmentedControl은 선택되었을 때와 선택되지 않았을 때를 구분할 수 있다.
이번에는 기본 옵션을 사용하지 않고 Custom 해보고자 한다.
// segment가 선택될 때의 색상. 현재 clear로 미적용
segment.selectedSegmentTintColor = .clear
이렇게 하면 segment가 선택되었을 때 색상이 미적용되게 된다.
더욱 커스텀하고 싶다면 아래와 같이 BackgroundImage와 segment DividerImage도 비활성화하면 된다.
// segment의 BackgroundImage를 적용하지 않고, 바 매트릭스를 기본 값으로 설정
segment.setBackgroundImage(UIImage(), for: .normal, barMetrics: .default)
// segment의 segment를 구분해주는 DividerImage도 적용하지 않고, 전부 기본 값으로 설정
segment.setDividerImage(UIImage(), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
return segment
}()
SegmentControl의 제약을 설정해주는 함수를 만들고,
func setUpSegmentControl() {
segmentControl.snp.makeConstraints {
$0.top.equalToSuperview().offset(131)
$0.leading.equalToSuperview().offset(16)
$0.trailing.equalToSuperview().offset(-16)
$0.height.equalTo(36)
}
다음과 같이 viewDidLoad에 추가해주면 된다.
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(segmentControl)
setUpSegmentControl()
}

⎮ UISegmentedContorller 하단에 UnderBar 추가하기
Segment 자체는 잘 구현되었는데 뭔가 허전하다.

다른 어플은 Segment 하단에 UnderBar가 있다.
이것도 같이 구현하면 완성도가 올라갈 것 같다.
하단 바는 UIView로 만들면 된다.
let barUnderLine: UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 250/255, green: 67/255, blue: 89/255, alpha: 1.0)
return view
}()
언더바도 마찬가지로 함수를 만들어 제약을 묶어주면 좋다.
func setUpUnderBar() {
let bar = barUnderLine
view.addSubview(bar)
bar.snp.makeConstraints {
$0.top.equalTo(segmentControl.snp.bottom).offset(7)
$0.width.equalTo(92)
$0.height.equalTo(2)
$0.leading.equalTo(segmentControl.snp.leading)
}
}
언더바의 위치는 버튼이 눌릴 때마다 바뀌어야하므로,
아래와 같이 세팅해주면 된다.
// 언더바의 위치를 바꿔주는 함수
@objc
func changeUnderBarPosition(_ segment: UISegmentedControl) {
// segment의 수를 저장
let segmentCount = segmentControl.numberOfSegments
// segmentControl의 너비에서 segmentCount를 나눠 4분할
let segmentWidth = segmentControl.bounds.width / CGFloat(segmentCount)
// leadingDistance가 0 -> 92.5 -> 185.0 -> 277.5로 Index에 따라 바뀜
let leadingDistance = CGFloat(segmentControl.selectedSegmentIndex) * segmentWidth
UIView.animate(withDuration: 0.2) {
// segment의 underLine의 제약을 업데이트 해주는 것
self.barUnderLine.snp.updateConstraints {
$0.leading.equalTo(self.segmentControl.snp.leading).offset(leadingDistance)
}
// 업데이트를 요청하면 바뀌도록 설정
self.segmentControl.layoutIfNeeded()
}
}
이후 addTarget을 통해 Value가 바뀌면 하단 바가 움직이도록 하면 된다.
// value가 바뀌면 하단바가 움직이도록 하는 selector 추가
segmentControl.addTarget(self, action: #selector(changeUnderBarPosition(_:)), for: .valueChanged)
마찬가지로 만들고 나면 viewDidLoad()에 추가해주면 된다.
override func viewDidLoad() {
......
setUpUnderBar()
}

'스파르타코딩 클럽 > 팀프로젝트' 카테고리의 다른 글
| 팀프로젝트2 [공유 킥보드 앱 만들기(1) - 디자인, 네이버 Maps API] (0) | 2025.04.26 |
|---|---|
| 팀프로젝트1 [주문 앱 만들기(5) - 데이터 바인딩, 앱 아이콘 적용하기, 앱 이름 한글로 바꾸기] (0) | 2025.04.11 |
| 팀프로젝트1 [주문 앱 만들기(4) - 데이터 바인딩] (0) | 2025.04.10 |
| 팀프로젝트1 [주문 앱 만들기(3) - View분리, Merge] (0) | 2025.04.09 |
| 팀프로젝트1 [주문 앱 만들기(1) - 디자인 비하인드, CustomFont] (0) | 2025.04.07 |