스위프트 하나를 통과하는 방법UI 뷰를 다른 뷰 구조의 변수로 사용
사용자 지정 탐색 링크(NavigationLink)를 구현하고 있습니다.MenuItem
프로젝트 전반에 걸쳐 재사용하고 싶습니다.그것은 그것에 부합하는 구조입니다.View
실행.var body : some View
그 안에 들어있는.NavigationLink
. 나는 어떻게든 제시할 견해를 저장할 필요가 있습니다.NavigationLink
의 몸속에MenuItem
하지만 아직 그렇게 하지 못했습니다.
정의했습니다.destinationView
인에MenuItem
로서의 몸.some View
그리고 두 개의 이니셜라이저를 시도했습니다.
너무 쉬워 보였습니다.
struct MenuItem: View {
private var destinationView: some View
init(destinationView: View) {
self.destinationView = destinationView
}
var body : some View {
// Here I'm passing destinationView to NavigationLink...
}
}
--> 오류: 프로토콜 'View'는 자체 또는 관련 유형 요구 사항이 있으므로 일반 제약 조건으로만 사용할 수 있습니다.
두 번째 시도:
struct MenuItem: View {
private var destinationView: some View
init<V>(destinationView: V) where V: View {
self.destinationView = destinationView
}
var body : some View {
// Here I'm passing destinationView to NavigationLink...
}
}
--> 오류: '일부 보기' 유형에 'V' 유형 값을 할당할 수 없습니다.
마지막 시도:
struct MenuItem: View {
private var destinationView: some View
init<V>(destinationView: V) where V: View {
self.destinationView = destinationView as View
}
var body : some View {
// Here I'm passing destinationView to NavigationLink...
}
}
--> 오류: '일부 보기' 유형에 '보기' 유형 값을 할당할 수 없습니다.
누가 도와줬으면 좋겠습니다.NavigationLink가 일부 보기를 인수로 받아들일 수 있는 경우 방법이 있어야 합니다.감사합니다;D
여기서 제가 읽은 모든 것과 저에게 효과가 있었던 해결책을 요약하자면 다음과 같습니다.
struct ContainerView<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
content
}
}
이것은 단순하게 표현할 수 있을 뿐만 아니라View
안에서, 또한 덕분에@ViewBuilder
,사용하다if-else
그리고.switch-case
블록:
struct SimpleView: View {
var body: some View {
ContainerView {
Text("SimpleView Text")
}
}
}
struct IfElseView: View {
var flag = true
var body: some View {
ContainerView {
if flag {
Text("True text")
} else {
Text("False text")
}
}
}
}
struct SwitchCaseView: View {
var condition = 1
var body: some View {
ContainerView {
switch condition {
case 1:
Text("One")
case 2:
Text("Two")
default:
Text("Default")
}
}
}
}
보너스: 가능한 모든 공간(부감에 필요한 공간만 요구하는 위의 컨테이너와는 반대로)을 요구하는 욕심쟁이 컨테이너를 원한다면 다음과 같습니다.
struct GreedyContainerView<Content: View>: View {
@ViewBuilder let content: Content
var body: some View {
content
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
보기에 이니셜라이저가 필요한 경우 다음을 사용할 수 있습니다.@ViewBuilder
파라미터도 마찬가지입니다.여러 개의 매개변수에 대해서도 다음을 수행할 수 있습니다.
init(@ViewBuilder content: () -> Content) {…}
애플이 하는 방식은 기능 빌더를 사용하는 것입니다.다음과 같은 사전 정의된 것이 있습니다.ViewBuilder
. 그것을 당신의 마지막 논쟁, 혹은 유일한 논쟁으로 삼으세요.init
방법MenuItem
, 다음과 같습니다.
..., @ViewBuilder builder: @escaping () -> Content)
다음과 같이 정의된 속성에 할당합니다.
let viewBuilder: () -> Content
그런 다음 전달된 보기를 표시하려면 다음과 같이 함수를 호출합니다.
HStack {
viewBuilder()
}
새 보기를 다음과 같이 사용할 수 있습니다.
MenuItem {
Image("myImage")
Text("My Text")
}
이렇게 하면 최대 10개의 보기를 통과하여 사용할 수 있습니다.if
조건 등이 더 제한적이기를 원한다면 자신의 함수 작성기를 정의해야 할 것입니다.나는 그렇게 하지 않았으니 당신은 그것을 검색해야 할 것입니다.
일반 매개 변수를 의 일부로 만들어야 합니다.MenuItem
:
struct MenuItem<Content: View>: View {
private var destinationView: Content
init(destinationView: Content) {
self.destinationView = destinationView
}
var body : some View {
// ...
}
}
다음과 같이 사용자 정의 보기를 만들 수 있습니다.
struct ENavigationView<Content: View>: View {
let viewBuilder: () -> Content
var body: some View {
NavigationView {
VStack {
viewBuilder()
.navigationBarTitle("My App")
}
}
}
}
struct ENavigationView_Previews: PreviewProvider {
static var previews: some View {
ENavigationView {
Text("Preview")
}
}
}
사용방법:
struct ContentView: View {
var body: some View {
ENavigationView {
Text("My Text")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
다음과 같이 Navigation Link(또는 기타 보기 위젯)를 변수로 하위 보기로 전달할 수 있습니다.
import SwiftUI
struct ParentView: View {
var body: some View {
NavigationView{
VStack(spacing: 8){
ChildView(destinationView: Text("View1"), title: "1st")
ChildView(destinationView: Text("View2"), title: "2nd")
ChildView(destinationView: ThirdView(), title: "3rd")
Spacer()
}
.padding(.all)
.navigationBarTitle("NavigationLinks")
}
}
}
struct ChildView<Content: View>: View {
var destinationView: Content
var title: String
init(destinationView: Content, title: String) {
self.destinationView = destinationView
self.title = title
}
var body: some View {
NavigationLink(destination: destinationView){
Text("This item opens the \(title) view").foregroundColor(Color.black)
}
}
}
struct ThirdView: View {
var body: some View {
VStack(spacing: 8){
ChildView(destinationView: Text("View1"), title: "1st")
ChildView(destinationView: Text("View2"), title: "2nd")
ChildView(destinationView: ThirdView(), title: "3rd")
Spacer()
}
.padding(.all)
.navigationBarTitle("NavigationLinks")
}
}
인정된 답변은 훌륭하고 간단합니다.iOS 14 + macOS 11로 구문이 더욱 깔끔해졌습니다.
struct ContainerView<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
content
}
}
그런 다음 계속 이렇게 사용합니다.
ContainerView{
...
}
저는 정말로 제 일을 하기 위해 노력했습니다.View
. 호출 방법에 대한 자세한 내용은 여기에 나와 있습니다.
확장자:View
(일반인 사용) - 기억하세요import SwiftUI
:
extension View {
/// Navigate to a new view.
/// - Parameters:
/// - view: View to navigate to.
/// - binding: Only navigates when this condition is `true`.
func navigate<SomeView: View>(to view: SomeView, when binding: Binding<Bool>) -> some View {
modifier(NavigateModifier(destination: view, binding: binding))
}
}
// MARK: - NavigateModifier
fileprivate struct NavigateModifier<SomeView: View>: ViewModifier {
// MARK: Private properties
fileprivate let destination: SomeView
@Binding fileprivate var binding: Bool
// MARK: - View body
fileprivate func body(content: Content) -> some View {
NavigationView {
ZStack {
content
.navigationBarTitle("")
.navigationBarHidden(true)
NavigationLink(destination: destination
.navigationBarTitle("")
.navigationBarHidden(true),
isActive: $binding) {
EmptyView()
}
}
}
}
}
또는 정적 함수 확장을 사용할 수도 있습니다.예를 들어 제목 표시줄을 텍스트로 확장합니다.이를 통해 코드를 재사용하기가 매우 쉽습니다.
이 경우 뷰 클로저가 있는 @Viewbuilder 래퍼를 전달하여 뷰에 맞는 사용자 지정 유형을 반환할 수 있습니다.예를 들어,
import SwiftUI
extension Text{
static func titleBar<Content:View>(
titleString:String,
@ViewBuilder customIcon: ()-> Content
)->some View {
HStack{
customIcon()
Spacer()
Text(titleString)
.font(.title)
Spacer()
}
}
}
struct Text_Title_swift_Previews: PreviewProvider {
static var previews: some View {
Text.titleBar(titleString: "title",customIcon: {
Image(systemName: "arrowshape.turn.up.backward")
})
.previewLayout(.sizeThatFits)
}
}
다른 보기에 두 개의 다른 보기를 전달하려고 하는데 이 오류 때문에 이 보기를 수행할 수 없는 경우:
식에 대한 진단을 생성하지 못했습니다. 버그 보고서를 제출하십시오.
<Content:처음 통과한 보기 >입니다. 처음 통과한 보기는 해당 유형을 저장하고, 통과 중인 두 번째 보기는 동일한 유형이어야 합니다. 이렇게 하면 텍스트와 이미지를 통과하려는 경우에는 통과할 수 없습니다.
솔루션은 간단합니다. 다른 컨텐츠 보기를 추가하고 이름을 다르게 지정합니다.
예:
struct Collapsible<Title: View, Content: View>: View {
@State var title: () -> Title
@State var content: () -> Content
@State private var collapsed: Bool = true
var body: some View {
VStack {
Button(
action: { self.collapsed.toggle() },
label: {
HStack {
self.title()
Spacer()
Image(systemName: self.collapsed ? "chevron.down" : "chevron.up")
}
.padding(.bottom, 1)
.background(Color.white.opacity(0.01))
}
)
.buttonStyle(PlainButtonStyle())
VStack {
self.content()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: collapsed ? 0 : .none)
.clipped()
.animation(.easeOut)
.transition(.slide)
}
}
}
보기 호출:
Collapsible {
Text("Collapsible")
} content: {
ForEach(1..<5) { index in
Text("\(index) test")
}
}
2개 보기에 대한 구문
struct PopOver<Content, PopView> : View where Content: View, PopView: View {
var isShowing: Bool
@ViewBuilder var content: () -> Content
@ViewBuilder var popover: () -> PopView
var body: some View {
ZStack(alignment: .center) {
self
.content()
.disabled(isShowing)
.blur(radius: isShowing ? 3 : 0)
ZStack {
self.popover()
}
.frame(width: 112, height: 112)
.opacity(isShowing ? 1 : 0)
.disabled(!isShowing)
}
}
}
언급URL : https://stackoverflow.com/questions/56938805/how-to-pass-one-swiftui-view-as-a-variable-to-another-view-struct
'programing' 카테고리의 다른 글
MySQL 연결이 많은 연결 오류로 차단된 이유는 무엇입니까? (0) | 2023.11.07 |
---|---|
jQuery를 사용하여 폭과 높이를 동적으로 설정하는 방법 (0) | 2023.11.07 |
Oracle 데이터 통합업체란 무엇입니까? (0) | 2023.11.07 |
RecordSet에서 오류 3001이 발생했습니다. 이유를 알 수 없습니다. (0) | 2023.11.07 |
가명일 때는 케이스로 그룹핑을 해주실 수 있나요? (0) | 2023.11.07 |