본문 바로가기
스파르타코딩 클럽/팀프로젝트

팀프로젝트1 [주문 앱 만들기(2) - UISegmentedControl]

by UDDT 2025. 4. 8.



 팀 프로젝트 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

  기본적인 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

 

    다른 어플은 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()
    }

 

 

최근댓글

최근글

skin by © 2024 ttuttak