SwiftUI/Controls & Tips
SegmentView
까칠코더
2023. 12. 30. 01:11
반응형
세그먼트 컨트롤을 사용하기 위해서는 기본 제공되는 Picker를 사용해서 .pickerStyle(SegmentedPickerStyle())을 적용해주면 됩니다.
(Picker를 이용한 Segment 사용방법 : https://kka7.tistory.com/221)
기본 디자인을 사용하면 좋은데 실제 프로젝트에서는 대부분 전혀 다른 디자인을 요구함으로써 직접 구현해야 할때가 있습니다.
다음 코드는 왼쪽과 오른쪽이 둥근 세그먼트 뷰에 대한 샘플이고,적용한 화면은 다음과 같습니다.
struct SegmentView<ID: Identifiable, Content: View>: View {
let segments: [ID]
@Binding var selected: ID
@ViewBuilder var content: (ID) -> Content
private let normalBorderColor = Color.gray
private let selectedBorderColor = Color.red
private let cornerRadius = CGFloat(20)
private let borderWidth = CGFloat(2)
var body: some View {
HStack(spacing: 0) {
let maxCount = segments.count
ForEach(Array(segments.enumerated()), id: \.offset) { index, segment in
let isSelected = selected.id == segment.id
let dividerColor: Color = {
if (!isSelected && index != maxCount - 1 && segments[safe: index - 1]?.id != segment.id) || index == 0 {
return normalBorderColor
} else {
return Color.clear
}
}()
let rectCorners: UIRectCorner = {
if index == 0 {
[.topLeft, .bottomLeft]
} else if index == maxCount - 1 {
[.topRight, .bottomRight]
} else {
[]
}
}()
Button {
selected = segment
} label: {
content(segment)
}
.overlay(
ZStack(alignment: .trailing) {
Rectangle()
.frame(width: borderWidth)
.foregroundColor(dividerColor)
.offset(x: borderWidth / 2)
RoundedCorner(radius: cornerRadius, corners: rectCorners)
.stroke(isSelected ? selectedBorderColor : Color.clear, lineWidth: borderWidth)
}
)
}
}
.background(
RoundedRectangle(cornerRadius: cornerRadius)
.stroke(normalBorderColor, lineWidth: borderWidth)
)
}
}
struct RoundedCorner: Shape {
let radius: CGFloat
let corners: UIRectCorner
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius * 2, height: radius * 2))
return Path(path.cgPath)
}
}
extension Array {
subscript(safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
사용한 예제
struct TestSegmentView: View {
enum Segment: Int, CustomStringConvertible, CaseIterable, Identifiable {
case zero, one, two, three, four
var description: String { "\(self.rawValue)" }
var id: Int { rawValue }
}
@State var selected: Segment = .zero
var body: some View {
VStack {
SegmentView(segments: Segment.allCases, selected: $selected) { segment in
Text(segment.description)
.foregroundColor(selected == segment ? Color.red : Color.gray)
.frame(width: 60, height: 40)
}
}
}
}
반응형