본문 바로가기

iOS/Deep dive!!!

[iOS] UISegmentedControl 탐구하기 | 세그먼트 컨트롤 커스텀 #1

 

안녕하세요. 

이번 포스트는 세그먼트 컨트롤의 사용 방법과 커스텀을 소개하려고 합니다.

 

https://developer.apple.com/design/human-interface-guidelines/segmented-controls

세그먼트 컨트롤은 items 개수에 따라 width가 같은 segment들이 있습니다. 

 

class ViewController {
  let segment = UISegmentedControl(items: ["Cherry Page", "Orange Page"])
  override func viewDidLoad() {
    super.viewDidLoad() 
    view.addSubivew(segemnt)
    NSLayoutConstraint.active([
      segment.leadingAnchor.constraint(equalTo: view.leadingAnchor),
      segment.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
      segment.trailingAnchor.constraint(equalTo: view.trailingAnchor),
      segment.heightAnchor.constraint(equalToConstant: 70])
  }

 

height과 레이아웃을 잡게된다면 이렇게 생성됩니다. 텍스트는 setTitleTextAttributes(attributes: for:) 를 통해 원하는 크기, 색 등을 지정할 수 있습니다.

 

segment.addTarget(self, action: #selector(didTapSegment), for: .valueChanged)

@objc func didTapSegment(_ sender: UISegmentedControl) { }

 

어느 위치가 선택되었는지는 addTarget을 통해서 세그먼트가 눌릴때마다 selectedSegmentIndex를 통해 확인이 가능합니다. 

 

func setSegment() {
  segment = UISegmentedControl(items: ["", ""]
  segment.setImage(UIImage(named:"cherry"), isImageBeforeText: true), forSegmentAt: 0)
  segment.setImage(UIImage(named:"orange"), isImageBeforeText: true), forSegmentAt: 1)
}

 

특정 세그먼트 index에 이미지를 지정할 수 있는데 이때 기존에 세그먼트 컨트롤 items의 초기화를 해주어야 합니다.

 

 

func setSegment() {
  ...
  let image = UIImage()
  segment.setBackgroundImage(image, for: .normal, barMetrics: .default)
  segment.setBackgroundImage(image, for: .selected, barMetrics: .default)
  segment.setBackgroundImage(image, for: .highlighted, barMetrics: .default)
}

 

세그먼트 컨트롤을 커스텀하기 위해서는기본적으로 지정된 divider, 백그라운드 색을 제거해야 합니다.  기본 백그라운드 색을 제거한 경우입니다.

 

 

func setSegment() {
  ...
  segment.setDividerImage(image, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
}

 

이렇게 divider 또한 제거한다면 모든 게 다 제거된 상태입니다.


 

UISegmentedControl은 기본적으로 텍스트 또는 이미지를 넣을 수 있습니다.

 

지금의 경우는 이미지 오른쪽에 텍스트를 새로 그려 이미지로 만들어서 각각의 segment에 넣은 것입니다. 이미지 안에 텍스트를 넣는 방법(스택 오버플로우 링크)

 

 

위 동영상은 세그먼트를 누를때마다 서로 다른 두 뷰를 전환하도록 만들었습니다.

 

private extension ViewController {
  @objc func didTapSegment(_ sender: UISegmentedControl) {
    guard !isAnimationWorking else { return }
    isAnimationWorking.toggle()
    let width = view.bounds.width
    guard segment.selectedSegmentIndex == 1 else {
      updateVisibleView(from: orangeView, to: cherryView, moveX: width)
      return
    }
    updateVisibleView(from: cherryView, to: orangeView, moveX: -width)
  }
  func updateVisibleView(from: UIView, to: UIView, moveX: CGFloat) {
    to.isHidden = false
    segment.isUserInteractionEnabled = false
    UIView.animate(
      withDuration: 0.38,
      delay: 0,
      options: .curveEaseOut,
      animations: {
        to.transform = .identity
        from.transform = .init(translationX: moveX, y: 0)
      }, completion: { _ in
        from.isHidden = true
        self.segment.isUserInteractionEnabled = true
        self.isAnimationWorking.toggle()
      })
  }
}

 

자세한 코드는 프로젝트 링크를 참고해주세요.

 

살짝 아쉬운 것은 세그먼트 컨트롤 init함수의 items에 text들을 입력했을 때, 세그먼트 안에 위치하는 레이블의 인스턴스를 가져오는 함수가 내장되어있지 않지만 또 여러 시도를 하니 세그먼트 안에 인스턴스를 있더라구요. 이는 다음 포스트에서 소개하려고 합니다: ]

 

 

프로젝트 코드: 

https://github.com/SHcommit/UIKitDeepDive/tree/master/Example-SegmentedControl/Default-SegmentedControl