스토리보드에 segmentcontrol를 추가합니다.
레이아웃 설정이 완료된 상태에서
//...
final class UnderlineSegmentedControl: UISegmentedControl {
private lazy var underlineView: UIView = {
let view = UIView()
view.backgroundColor = .black
addSubview(view)
return view
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
self.removeBackgroundAndDivider()
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.gray], for: .normal)
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 13, weight: .semibold)], for: .selected)
}
private func removeBackgroundAndDivider() {
let image = UIImage()
self.setBackgroundImage(image, for: .normal, barMetrics: .default)
self.setBackgroundImage(image, for: .selected, barMetrics: .default)
self.setBackgroundImage(image, for: .highlighted, barMetrics: .default)
self.setDividerImage(image, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
}
override func layoutSubviews() {
super.layoutSubviews()
let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(self.selectedSegmentIndex)
let height = CGFloat(2.0)
let yPosition = self.bounds.size.height - height
underlineView.frame = CGRect(x: underlineFinalXPosition, y: yPosition, width: self.bounds.width / CGFloat(self.numberOfSegments), height: height)
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
self.selectedSegmentIndex = 0
}
}
UnderlineSegmentedControl
는 스토리보드에서 구성한 후에 해당하는 클래스를 지정합니다
init?(coder: NSCoder)
는 segment control에 대한 초기 설정을 수행합니다.
layoutSubviews
는 underlineView의 프레임을 업데이트합니다.
willMove(toSuperview:)
메소드에서 초기 선택된 segment를 0으로 설정했는데, 뷰가 슈퍼뷰에 추가될 때 호출되는 메소드입니다.
자연스럽게 전환되는 애니메이션 추가
UnderlineSegmentedControl
의 선택된 세그먼트가 바뀔 때 underlineView가 자연스럽게 넘어가도록 하려면, valueChanged
이벤트를 감지하고 애니메이션을 추가해야 합니다.
먼저, init?(coder: NSCoder) 메소드 내에 valueChanged 이벤트를 감지하는 코드를 추가
required init?(coder: NSCoder) { super.init(coder: coder)
self.removeBackgroundAndDivider() self.setTitleTextAttributes([
NSAttributedString.Key.foregroundColor: UIColor.gray], for: .normal)
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.green,
.font: UIFont.systemFont(ofSize: 13, weight: .semibold)], for: .selected) self.addTarget(self, action: #selector(segmentedControlValueChanged(_:)), for: .valueChanged) }
그리고 @objc 어노테이션이 달린 segmentedControlValueChanged(_:) 메소드를 추가합니다. 이 메소드는 valueChanged 이벤트가 발생했을 때 호출되며, underlineView를 새로 선택된 세그먼트 아래로 애니메이션으로 움직이게 합니다.
@objc private func segmentedControlValueChanged(_ sender: UISegmentedControl)
{ let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(self.selectedSegmentIndex) UIView.animate(withDuration: 0.3)
{ self.underlineView.frame.origin.x = underlineFinalXPosition }
전체코드
final class UnderlineSegmentedControl: UISegmentedControl {
private lazy var underlineView: UIView = {
let view = UIView()
view.backgroundColor = .black
addSubview(view)
return view
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
self.removeBackgroundAndDivider()
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.gray], for: .normal)
self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black, .font: UIFont.systemFont(ofSize: 13, weight: .semibold)], for: .selected)
self.addTarget(self, action: #selector(segmentedControlValueChanged(_:)), for: .valueChanged)
}
private func removeBackgroundAndDivider() {
let image = UIImage()
self.setBackgroundImage(image, for: .normal, barMetrics: .default)
self.setBackgroundImage(image, for: .selected, barMetrics: .default)
self.setBackgroundImage(image, for: .highlighted, barMetrics: .default)
self.setDividerImage(image, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
}
override func layoutSubviews() {
super.layoutSubviews()
let height = CGFloat(2.0)
let yPosition = self.bounds.size.height - height
underlineView.frame = CGRect(x: underlineView.frame.origin.x, y: yPosition, width: self.bounds.width / CGFloat(self.numberOfSegments), height: height)
}
@objc private func segmentedControlValueChanged(_ sender: UISegmentedControl) {
let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(self.selectedSegmentIndex)
UIView.animate(withDuration: 0.3) {
self.underlineView.frame.origin.x = underlineFinalXPosition
}
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
self.selectedSegmentIndex = 0
}
'IOS - Swift' 카테고리의 다른 글
[WWDC 2022]Create parametric 3D room scans with RoomPlan (0) | 2023.06.11 |
---|---|
[iOS/Swift] Png 한장으로 애니메이션 효과주기 - CABasicAnimation (0) | 2023.06.04 |
[iOS/Swift] accesstoken 저장이 안될때 (0) | 2023.05.21 |
[Swift/에러해결] [NSNUll pointsize] Sizunrecognized selector sent to instance (0) | 2023.03.29 |
[iOS/Xcode] CocoaPods 설치 오류(gem) (0) | 2023.03.03 |