SwiftUI:在使用常量与@Binding 初始值设定项时了解 .sheet/.fullScreenCover 生命周期

标签 swift xcode swiftui

我试图了解如何以及何时调用 .sheet 和 .fullScreenCover 初始值设定项。下面是一个最小的可重现示例,其中第一个屏幕有 3 个彩色矩形,SecondView(通过 .fullScreenCover 显示)有一个矩形根据从第一个屏幕中选择的颜色改变颜色。

  • 应用首次加载时,颜色设置为灰色。
  • 如果我点击绿色矩形,SecondView 会显示一个灰色矩形。 (即颜色没有正确改变)。
  • 如果我随后关闭 SecondView 并点击红色矩形,SecondView 会显示一个红色矩形。 (即颜色 DID 正确更改。)

那么,我想知道为什么这个设置在初始加载时不起作用,但在第 2/3 次尝试时起作用?

注意:我知道这可以通过将“let selectedColor”更改为 @Binding 变量来解决,这不是我要问的。

代码:

import SwiftUI

    struct SegueTest: View {
        
        @State var showSheet: Bool = false
        @State var color: Color = .gray
        
        var body: some View {
            HStack {
                RoundedRectangle(cornerRadius: 25)
                    .fill(Color.red)
                    .frame(width: 100, height: 100)
                    .onTapGesture {
                        color = .red
                        showSheet.toggle()
                    }
                
                RoundedRectangle(cornerRadius: 25)
                    .fill(Color.green)
                    .frame(width: 100, height: 100)
                    .onTapGesture {
                        color = .green
                        showSheet.toggle()
                    }
    
                RoundedRectangle(cornerRadius: 25)
                    .fill(Color.orange)
                    .frame(width: 100, height: 100)
                    .onTapGesture {
                        color = .orange
                        showSheet.toggle()
                    }
    
            }
            .fullScreenCover(isPresented: $showSheet, content: {
                SecondView(selectedColor: color)
            })
        }
    }
    
    struct SecondView: View {
        
        @Environment(\.presentationMode) var presentationMode
        let selectedColor: Color // Should change to @Binding
        
        var body: some View {
            ZStack {
                Color.black.edgesIgnoringSafeArea(.all)
                
                RoundedRectangle(cornerRadius: 25)
                    .fill(selectedColor)
                    .frame(width: 300, height: 300)
            }
            .onTapGesture {
                presentationMode.wrappedValue.dismiss()
            }
        }
    
    }
    
    struct SegueTest_Previews: PreviewProvider {
        static var previews: some View {
            SegueTest()
        }
    }

最佳答案

查看注释和print 语句。尤其是红色

import SwiftUI

struct SegueTest: View {
    
    @State var showSheet: Bool = false{
        didSet{
            print("showSheet :: didSet")
        }
        willSet{
            print("showSheet :: willSet")
        }
    }
    @State var color: Color = .gray{
        didSet{
            print("color :: didSet :: \(color.description)")
        }
        willSet{
            print("color :: willSet :: \(color.description)")
        }
    }
    @State var refresh: Bool = false
    init(){
        print("SegueTest " + #function)
    }
    var body: some View {
        print(#function)
        return HStack {
            //Just to see what happens when you recreate the View
            //Text(refresh.description)
            Text(color.description)
            RoundedRectangle(cornerRadius: 25)
                .fill(Color.red)
                .frame(width: 100, height: 100)
                .onTapGesture {
                    print("SegueTest :: onTapGesture :: red")
                    //Changing the color
                    color = .red
                    //Refreshed SegueTest reloads function
                    //refresh.toggle()
                    showSheet.toggle()
                }
            
            RoundedRectangle(cornerRadius: 25)
                .fill(Color.green)
                .frame(width: 100, height: 100)
                .onTapGesture {
                    print("SegueTest :: onTapGesture :: green")
                    //Changing the color
                    color = .green
                    showSheet.toggle()
                }
            
            RoundedRectangle(cornerRadius: 25)
                .fill(Color.orange)
                .frame(width: 100, height: 100)
                .onTapGesture {
                    print("SegueTest :: onTapGesture :: orange")
                    //Changing the color
                    color = .orange
                    showSheet.toggle()
                }
            
        }
        //This part is likely created when SegueTest is created and since a struct is immutable it keeps the original value
        .fullScreenCover(isPresented: $showSheet, content: {
            SecondView(selectedColor: color)
        })
    }
}

struct SecondView: View {
    
    @Environment(\.presentationMode) var presentationMode
    //struct is immutable
    let selectedColor: Color // Should change to @Binding
    init(selectedColor: Color){
        print("SecondView " + #function)
        self.selectedColor = selectedColor
        print("SecondView :: struct :: selectedColor = \(self.selectedColor.description)" )
        print("SecondView :: parameter :: selectedColor = \(selectedColor.description)" )
    }
    var body: some View {
        ZStack {
            Color.black.edgesIgnoringSafeArea(.all)
            
            RoundedRectangle(cornerRadius: 25)
                .fill(selectedColor)
                .frame(width: 300, height: 300)
        }
        .onTapGesture {
            presentationMode.wrappedValue.dismiss()
        }
    }
    
}

struct SegueTest_Previews: PreviewProvider {
    static var previews: some View {
        SegueTest()
    }
}

关于SwiftUI:在使用常量与@Binding 初始值设定项时了解 .sheet/.fullScreenCover 生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65281559/

相关文章:

ios - 如何在用户登录后自动更新 ViewController

ios - 是否可以使用 MusicKit 获取轨道预览

swift - 如何让用户看到他们关注的帖子显示在帖子提要上

ios - UIImage 与 UIAlertController 中的 UITextField 重叠

swift - 如何访问 SwiftUI Canvas 中的像素数据

swift +终端

iphone - 如何从 UIView/UIScrollView 创建图像

swift - Xcode Swift 3 计时器错误

swift - 获取 ScrollView 在 SwiftUI 中的当前位置?

autocomplete - 如何使用 ZStack & Geometry 定位列表?