iOS/UIKit

[UIKit] UISegmentedControl 사용해보기

kyxxn 2024. 6. 17. 15:43
728x90

학습 목표

  • UISegmentedControl 개념 알기
  • UISegmentedControl 실습 및 꾸며보기
  • toduck 프로젝트에 사용되는 View 만들어보기


학습 내용

  • UIResponder - UIView - UIControl - UISegmentedControl

UISegmentedControl의 기본값

Image

  • 선택된 버튼의 BackgroundImage
  • 선택되지 않은 버튼의 BackgroundImage
  • 버튼 사이의 DivderImage

Text

  • 선택된 버튼의 TextColor & FontSize
  • 선택되지 않은 버튼의 TextColor & FontSize

UISegmentedControl 꾸미기

class MainViewController: UIViewController {

        private let segmentedControl = UISegmentedControl(items: ["전체", "소통", "질문"]).then {
        $0.selectedSegmentIndex = 0
        $0.backgroundColor = .clear
        $0.addTarget(self, action: #selector(segmentedChanged(_:)), for: .valueChanged)

        // 세그먼트 컨트롤 외형 커스터마이징
        $0.setBackgroundImage(UIImage(), for: .normal, barMetrics: .default)
        $0.setBackgroundImage(UIImage(), for: .selected, barMetrics: .default)
        $0.setDividerImage(UIImage(), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)

        // 선택안된 버튼의 폰트 & 색상 설정
        let normalAttributes: [NSAttributedString.Key: Any] = [
            .foregroundColor: UIColor.lightGray,
            .font: UIFont.systemFont(ofSize: 14)
        ]
        $0.setTitleTextAttributes(normalAttributes, for: .normal)

        // 선택된 버튼의 폰트 & 색상 설정
        let selectedAttributes: [NSAttributedString.Key: Any] = [
            .foregroundColor: UIColor.black,
            .font: UIFont.systemFont(ofSize: 14)
        ]
        $0.setTitleTextAttributes(selectedAttributes, for: .selected)
    }

    private let containerView = UIView()

    @objc func segmentedChanged(_ sender: UISegmentedControl) {
        // 선택된 세그먼트에 따라 뷰 컨트롤러를 전환
        switch sender.selectedSegmentIndex {
        case 0:
            transitionToViewController(homeViewController)
        case 1:
            transitionToViewController(groupViewController)
        default:
            break
        }
        // 선택된 세그먼트에 맞게 선의 위치를 업데이트
        updateUnderlinePosition(animated: true)
    }

    private func transitionToViewController(_ viewController: UIViewController) {
        // 기존 컨테이너 뷰의 서브뷰를 모두 제거
        for subview in containerView.subviews {
            subview.removeFromSuperview()
        }

        // 새로운 뷰 컨트롤러의 뷰를 컨테이너 뷰에 추가
        containerView.addSubview(viewController.view)
        viewController.view.frame = containerView.bounds
        viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        viewController.didMove(toParent: self)
    }

    func layout() {
        segmentedControl.snp.makeConstraints {
            $0.top.equalTo(view.safeAreaLayoutGuide).offset(10)
            $0.leading.equalTo(view).offset(20)
            $0.trailing.equalTo(view).offset(-20)
            $0.height.equalTo(30) // 필요한 높이로 설정
        }

        containerView.snp.makeConstraints {
            $0.top.equalTo(grayLineView.snp.bottom).offset(10)
            $0.leading.trailing.bottom.equalTo(view)
        }
    }
}

실행 화면

UIView 추가해서 디테일 꾸미기

class MainViewController: UIViewController {

    private let underlineView = UIView().then {
        $0.backgroundColor = .black
    }

    private let grayLineView = UIView().then {
        $0.backgroundColor = .lightGray
    }

    func layout() {
        // grayLineView의 레이아웃 설정 (세그먼트 컨트롤 아래의 긴 회색 선)
        grayLineView.snp.makeConstraints {
            $0.top.equalTo(segmentedControl.snp.bottom)
            $0.leading.equalTo(segmentedControl.snp.leading)
            $0.trailing.equalTo(segmentedControl.snp.trailing)
            $0.height.equalTo(1)
        }

        // underlineView의 레이아웃 설정 (선택된 세그먼트 아래의 검정색 선)
        underlineView.snp.makeConstraints {
            $0.top.equalTo(segmentedControl.snp.bottom)
            $0.height.equalTo(1.5)
            $0.width.equalTo(segmentedControl.snp.width).dividedBy(segmentedControl.numberOfSegments)
            $0.leading.equalTo(segmentedControl.snp.leading)
        }
    }

    private func updateUnderlinePosition(animated: Bool) {
        // 세그먼트의 너비 계산
        let segmentWidth = segmentedControl.frame.width / CGFloat(segmentedControl.numberOfSegments)
        // 선택된 세그먼트의 위치 계산
        let leadingDistance = segmentWidth * CGFloat(segmentedControl.selectedSegmentIndex)

        // 애니메이션 여부에 따라 위치 업데이트
        if animated {
            UIView.animate(withDuration: 0.3) {
                self.underlineView.snp.updateConstraints {
                    $0.leading.equalTo(self.segmentedControl.snp.leading).offset(leadingDistance)
                }
                self.view.layoutIfNeeded()
            }
        } else {
            underlineView.snp.updateConstraints {
                $0.leading.equalTo(segmentedControl.snp.leading).offset(leadingDistance)
            }
        }
    }
}

실행화면


배운 점

  • UISegmentedControl 커스텀 해보기

참조 링크

UISegmentedControl | Apple Developer Documentation

 

UISegmentedControl | Apple Developer Documentation

A horizontal control that consists of multiple segments, each segment functioning as a discrete button.

developer.apple.com

 

[iOS - swift] 2. UISegmentedControl - 커스텀 방법, PageViewController와 사용 방법

 

[iOS - swift] 2. UISegmentedControl - 커스텀 방법, PageViewController와 사용 방법

1. UISegmentedControl - 기본 사용 방법 2. UISegmentedControl - 커스텀 방법, PageViewController와 사용 방법 UISegmentedControl 커스텀 방법 클래스 준비 import UIKit final class UnderlineSegmentedControl: UISegmentedControl { } UISeg

ios-development.tistory.com