안녕하세요.
이번 포스트는 세그먼트 컨트롤의 사용 방법과 커스텀을 소개하려고 합니다.
세그먼트 컨트롤은 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들을 입력했을 때, 세그먼트 안에 위치하는 레이블의 인스턴스를 가져오는 함수가 내장되어있지 않지만 또 여러 시도를 하니 세그먼트 안에 인스턴스를 있더라구요. 이는 다음 포스트에서 소개하려고 합니다: ]
프로젝트 코드:
'iOS > Deep dive!!!' 카테고리의 다른 글
[iOS] Dynamic TableViewCell in Runtime(with animation) | 테이블뷰 Deep dive #1 사전 지식 (0) | 2023.11.04 |
---|---|
[iOS] 알림 아이콘이 보여지는 언더바 세그먼트 | 세그먼트 컨트롤 커스텀 #2 (0) | 2023.10.31 |
[iOS] 뷰 컨트롤러 강한 참조 발생 경험와 해결 방법. Strong reference closure | ARC 진짜 뿌수기 #1 (0) | 2023.10.22 |
[iOS] 컬랙션 뷰 Flow -> Compositional layout으로 리펙터링하기 #1 (0) | 2023.10.01 |