귀찮음 이슈로 2주 묵혀있던 이슈인데 미루면 더 안쓸거 같아 대충씀.
회사에서 드랍다운을 만들일이 생겼는데, 만들기로함. 근데 문제가 생김. 드랍다운 메뉴를 펼치면 아래의 뷰 위를 덮여야 하는데, 도저히 위로 올라오지 않음. 스택오버플로우를 보면 SceneStorage로 이러쿵 저러쿵 하는데, 도저히 먹히지 않는다. zIndex도 잘 안됨 ㅇㅇ
DropDown을 화면마다 하나하나 하드코딩 할수는 없고, 내 유일한 구세주인 KavSoft 영상을 찾아보다 발견, 그대로 클론코딩을 했다.
Animated Drop Down Picker - SwiftUI
이 영상인데, 코드를 나는 여기서 그대로 썼으니까 코드를 대놓고 까긴 좀 그렇고, 저기의 드랍다운 코드를 제외하고 나머지, 어떻게 내가 재사용이 가능하면서 깔쌈하게 만들었는지, 아이디어는 무엇인지 알려드림.
Protocol을 하나 만들고, 그 프로토콜을 충족하면 드랍다운을 할 수 있도록 만들고 싶었다. enum으로 할건데, protocol이 무조건 enum만 하게 할수는 없어서 CaseIterable을 채택해서 다른 타입으로 하려고 하는 사람들에게 귀찮음을 주도록 하자. 프로토콜은 꽤나 간단하다.
protocol Selectable: Hashable, CaseIterable {
var title: String { get }
}
그리고 대충 하나 만들어보자.
enum TestSelect: String {
case a = "AAA"
case b = "BBB"
case c = "CCC"
}
extension TestSelect: Selectable {
var title: String {
return rawValue
}
}
rawValue를 이용하면 더 쉽게 프로토콜을 충족시킬 수 있다.
struct DropdownConfig<T: Selectable> {
var active: T
var show: Bool = false
var showContent: Bool = false
var anchor: CGRect = .zero
var cornerRadius: CGFloat = 12
}
그다음, 제네릭을 이용해서 이렇게 만들어준다. 이러면 그 누가 들어와도 재사용이 가능하도록 만들 수 있다.
struct DropdownView<T: Selectable>: View {
var values: T.AllCases
@Binding var config: DropdownConfig<T>
var body: some View {
VStack(spacing: 0) {
ForEach(Array(values), id: \.self) { item in
.....
물론 뷰도 제네릭을 받을 수 있도록 만들어준다.
struct ContentView: View {
@State var config = DropdownConfig(active: TestSelect.a)
@State var config2 = DropdownConfig(active: TestSelect.b)
@State var config3 = DropdownConfig(active: TestSelect.c)
var body: some View {
ScrollView {
SourceDropdownView(config: $config)
SourceDropdownView(config: $config2)
SourceDropdownView(config: $config3)
}
.dropdownOverlay($config)
.dropdownOverlay($config2)
.dropdownOverlay($config3)
}
}
잘된다