Swift에서 switch 문에 대한 대안UI View Builder 블록?
⚠2024 2020년 6월 23일 편집: Xcode 12부터는 ViewBuilder에서 switch 및 iflet 문이 모두 지원됩니다.
스위프트를 사용하여 내 앱을 복제하려고 했습니다.UI. 열거형 값에 따라 다른 하위 보기 컨트롤러를 표시하는 RootViewController가 있습니다.스위프트에서처럼보기 컨트롤러 대신 보기를 사용하는 UI, 내 코드는 다음과 같습니다.
struct RootView : View {
@State var containedView: ContainedView = .home
var body: some View {
// custom header goes here
switch containedView {
case .home: HomeView()
case .categories: CategoriesView()
...
}
}
}
유감스럽게도 경고가 표시됩니다.
컨트롤 흐름 문을 포함하는 폐쇄는 함수 작성기에서 사용할 수 없습니다.
그러면 이 동작을 복제할 수 있도록 전환할 수 있는 대안이 있을까요?
⚠2024 2020년 6월 23일 편집:Xcode 12부터는 ViewBuilder에서 switch 및 iflet 문이 모두 지원됩니다.
답변 감사합니다, 여러분.저는 애플의 개발 포럼에서 해결책을 찾았습니다.킬 길라드가 답했습니다.해결책은 Lu_, Linus, Mo가 제안한 기능으로 스위치를 추출하는 것이지만, 우리는 뷰를 다음과 같이 포장해야 합니다.AnyView
다음과 같이 작동합니다.
struct RootView: View {
@State var containedViewType: ContainedViewType = .home
var body: some View {
VStack {
// custom header goes here
containedView()
}
}
func containedView() -> AnyView {
switch containedViewType {
case .home: return AnyView(HomeView())
case .categories: return AnyView(CategoriesView())
...
}
}
업데이트: 스위프트UI 2는 이제 함수 빌더, https://github.com/apple/swift/pull/30174 에서 스위치 문을 지원합니다.
니콜라이의 대답에 덧붙여, 스위치를 컴파일하게 했지만 전환에는 작동하지 않았습니다. 여기 전환을 지원하는 그의 예 버전이 있습니다.
struct RootView: View {
@State var containedViewType: ContainedViewType = .home
var body: some View {
VStack {
// custom header goes here
containedView()
}
}
func containedView() -> some View {
switch containedViewType {
case .home: return AnyView(HomeView()).id("HomeView")
case .categories: return AnyView(CategoriesView()).id("CategoriesView")
...
}
}
에 하십시오.id(...)
각 AnyView에 추가되었습니다.이렇게 하면 Swift가 가능합니다.UI는 뷰 계층 내에서 뷰를 식별하여 전환 애니메이션을 올바르게 적용할 수 있도록 합니다.
의 반환 유형을 지정하면 별도의 함수에 스위치 문을 추출할 필요가 없는 것 같습니다.ViewBuilder
예:
Group { () -> Text in
switch status {
case .on:
return Text("On")
case .off:
return Text("Off")
}
}
참고: 임의의 보기 유형을 다음으로 묶어서 반환할 수도 있습니다.
AnyView
반환 유형으로 지정합니다.
에 열거형을 사용할 수 있습니다.@ViewBuilder
하기와 같이...
열거형 지우기
enum Destination: CaseIterable, Identifiable {
case restaurants
case profile
var id: String { return title }
var title: String {
switch self {
case .restaurants: return "Restaurants"
case .profile: return "Profile"
}
}
}
이제 보기 파일에서
struct ContentView: View {
@State private var selectedDestination: Destination? = .restaurants
var body: some View {
NavigationView {
view(for: selectedDestination)
}
}
@ViewBuilder
func view(for destination: Destination?) -> some View {
switch destination {
case .some(.restaurants):
CategoriesView()
case .some(.profile):
ProfileView()
default:
EmptyView()
}
}
}
NavigationLink에서 동일한 사례를 사용하려는 경우...다음과 같이 사용할 수 있습니다.
struct ContentView: View {
@State private var selectedDestination: Destination? = .restaurants
var body: some View {
NavigationView {
List(Destination.allCases,
selection: $selectedDestination) { item in
NavigationLink(destination: view(for: selectedDestination),
tag: item,
selection: $selectedDestination) {
Text(item.title).tag(item)
}
}
}
}
@ViewBuilder
func view(for destination: Destination?) -> some View {
switch destination {
case .some(.restaurants):
CategoriesView()
case .some(.profile):
ProfileView()
default:
EmptyView()
}
}
}
같이 보기로 묶어야 .VStack
또는Group
:
var body: some View {
Group {
switch containedView {
case .home: HomeView()
case .categories: CategoriesView()
...
}
}
}
또는 반환 값을 추가할 수 있습니다.
var body: some View {
switch containedView {
case .home: return HomeView()
case .categories: return CategoriesView()
...
}
}
그러나 이 문제를 해결하는 가장 좋은 방법은 보기를 반환하는 방법을 만드는 것입니다.
func nextView(for containedView: YourViewEnum) -> some AnyView {
switch containedView {
case .home: return HomeView()
case .categories: return CategoriesView()
...
}
}
var body: some View {
nextView(for: containedView)
}
» default
의 진술.switch
나를 위해 해결했습니다.
struct RootView : View {
@State var containedView: ContainedView = .home
var body: some View {
// custom header goes here
switch containedView {
case .home: HomeView()
case .categories: CategoriesView()
...
default: EmptyView()
}
}
}
래퍼로 할 수 있습니다 보기
struct MakeView: View {
let make: () -> AnyView
var body: some View {
make()
}
}
struct UseMakeView: View {
let animal: Animal = .cat
var body: some View {
MakeView {
switch self.animal {
case .cat:
return Text("cat").erase()
case .dog:
return Text("dog").erase()
case .mouse:
return Text("mouse").erase()
}
}
}
}
AnyView()를 사용하지 않는 경우.여러 if 문을 사용하고 관련 값을 검색하기 위해 Enum에 Equatable 및 CustomStringConvertible 프로토콜을 구현합니다.
var body: some View {
ZStack {
Color("background1")
.edgesIgnoringSafeArea(.all)
.onAppear { self.viewModel.send(event: .onAppear) }
// You can use viewModel.state == .loading as well if your don't have
// associated values
if viewModel.state.description == "loading" {
LoadingContentView()
} else if viewModel.state.description == "idle" {
IdleContentView()
} else if viewModel.state.description == "loaded" {
LoadedContentView(list: viewModel.state.value as! [AnimeItem])
} else if viewModel.state.description == "error" {
ErrorContentView(error: viewModel.state.value as! Error)
}
}
}
그리고 저는 다음과 같은 구조를 사용하여 제 견해를 분리할 것입니다.
struct ErrorContentView: View {
var error: Error
var body: some View {
VStack {
Image("error")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
Text(error.localizedDescription)
}
}
}
언급URL : https://stackoverflow.com/questions/56736466/alternative-to-switch-statement-in-swiftui-viewbuilder-block
'programing' 카테고리의 다른 글
문자열 시작 부분에 텍스트 추가 (0) | 2023.08.22 |
---|---|
셀렉트 박스 스타일이 가능한가요? (0) | 2023.08.22 |
UIScrollView 콘텐츠의 표시된 정류 가져오기 (0) | 2023.08.22 |
덤프 파일 MySQL 5.6.10 (0) | 2023.08.22 |
개인 도커 레지스트리에서 이미지를 삭제하는 방법은 무엇입니까? (0) | 2023.08.22 |