본문 바로가기
공부/스위프트

[스위프트] UIKit custom segmented control

by 초코팅촉 2024. 6. 23.
728x90

이번시간에는 UIKit에서 세그멘트 컨트롤을 커스텀해서 쓰느법을 알아보려고 합니다.

다른글들을 많이 찾아봤는데 다들 스냅킷만 쓰더라구요?

이번 프로젝트는 스냅킷을 쓸만큼 뭐가 많지않아서 그냥 만들기로해서

하루죙일 스냅킷 안쓰고 그걸 똑같이 그대로 UIKit 네이티브 코드로 옮겨서 했는데 안되더라구요...

그래서 해외글도 찾아보니까 그냥 x좌표를 옮겨버리더라구요?(진즉에 찾아볼껄;;)

 

그래서 나온 코드입니다.. 와 진짜 너무 힘들었어요ㅠㅠ

우선 결과물은 아래와 같습니다.

 

custom Segmented Control

 

그럼 코드로 보시죠~

예시코드

private let segmentControl: UISegmentedControl = {
	let segment = UISegmentedControl()
	segment.insertSegment(withTitle: "Month", at: 0, animated: true)
	segment.insertSegment(withTitle: "Day", at: 1, animated: true)
	segment.selectedSegmentIndex = 0
            
	segment.setTitleTextAttributes([
		NSAttributedString.Key.foregroundColor: UIColor.gray,
		NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .normal)
    segment.setTitleTextAttributes([
        NSAttributedString.Key.foregroundColor: UIColor.black,
        NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], for: .selected)
    segment.selectedSegmentTintColor = .clear
    segment.setBackgroundImage(UIImage(), for: .normal, barMetrics: .default)
    segment.setDividerImage(UIImage(), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
            
    segment.addTarget(self, action: #selector(changeUnderLinePosition), for: .valueChanged)
            
    segment.translatesAutoresizingMaskIntoConstraints = false
    return segment
}()

private let underLineView: UIView = {
    let view = UIView()
    view.backgroundColor = .black
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

우선은 위와 같이

두개의 세그먼트를 갖는 세그먼트 컨트롤과 밑줄을 위한 뷰를 만들어줍니다.

 

override func viewDidLoad() {
	super.viewDidLoad()
    
    self.view.addSubview(segmentControl)
    self.view.addSubview(underLineView)
    
    let safeArea = self.view.safeAreaLayoutGuide
    NSLayoutConstraint.activate([
        segmentControl.topAnchor.constraint(equalTo: safeArea.topAnchor),
        segmentControl.centerXAnchor.constraint(equalTo: safeArea.centerXAnchor),
        segmentControl.widthAnchor.constraint(equalTo: safeArea.widthAnchor, multiplier: 0.4),
        segmentControl.heightAnchor.constraint(equalToConstant: 20),
            
        underLineView.topAnchor.constraint(equalTo: segmentControl.bottomAnchor, constant: 10),
        underLineView.leadingAnchor.constraint(equalTo: segmentControl.leadingAnchor),
        underLineView.widthAnchor.constraint(equalTo: segmentControl.widthAnchor, multiplier: 0.5),
        underLineView.heightAnchor.constraint(equalToConstant: 2)

    ])
}

그다음 뷰를 현재 뷰컨에 추가해주고

segmentControl과 underLineView를 각각 제약조건을 추가해줍시다.

너무 간단해서 딱히 설명할게 없죠?

 

@objc
private func changeUnderLinePosition(_ segment: UISegmentedControl) {
    let halfWidth = segmentControl.frame.width / 2
    let xPosition = segmentControl.frame.origin.x + (halfWidth * CGFloat(segmentControl.selectedSegmentIndex))
            
    UIView.animate(withDuration: 0.2) {
        self.underLineView.frame.origin.x = xPosition
    }
}

마지막으로 underLine을 움직이기 위한 메서드를 만들어줍니다.

지금은 세그먼트가 두개니까 halfWidth라고 반쪽넓이를 구했는데 동적으로 조절한다면 뒤에 나누는 숫자를

segmentControl.numberOfSegments를 쓰면 좋을거같습니다.

 

다음으로 xPosition 변수를 만들어줍니다.

underLine이 맨처음에 segmentControl과 leading이 일치했죠?

그래서 xPosition은 segmentControl의 x좌표에 인덱스(0,1)에 맞춰서

0일땐 초기 위치, 1일땐 너비의 절반만큼 더해서 옮깁니다.

 

그리고 animate()를 통해서 0.2초동안 애니메이션과 함께 x좌표를 바꿔서 부드럽게 움직이는것처럼 만들어줍니다.

 

 

아래 두개의 글을 참고했습니다.

https://mini-min-dev.tistory.com/226

 

[UISegmentedControl] 상단 커스텀 탭바를 만들어봅시다! (1) - UISegmentedControl 활용

1️⃣ 오늘 만들어줄 화면은? 합동 세미나 과제로 테이블링 어플을 클론코딩하면서 만들었던 상단 커스텀 탭바의 내용을 정리해보겠다. 여러 글들을 찾아봤을 때, 상단 커스텀 탭바를 만들어주

mini-min-dev.tistory.com

 

https://nitishrajput912.medium.com/underline-segment-control-programmatically-swift-d2924842621a

 

Underline segment control programmatically (Swift)

In this article, we will create Underline segment control programmatically in 2 simple steps:

nitishrajput912.medium.com