简体   繁体   中英

SwiftUI: Why isn't my view being shown off-screen as its frame suggests it should?

I have an interface where I want to be able to toggle a Side Menu and also a toolbar. The Side Menu slides in/out from the right and the Toolbar from the bottom.

I'm making it generic so it's reusable to whatever content one wants to use.

The code is this:

struct ControlsOverlayView<ToolbarContent: View, MenuContent: View>: View {
    
    let menuWidth: CGFloat
    let isMenuActive: Bool
    let onMenuHide: () -> Void
    
    let menuContent: MenuContent
    
    let toolbarHeight: CGFloat
    let isToolbarActive: Bool
    let onToolbarHide: () -> Void
    
    let toolbarContent: ToolbarContent
    
    init(menuWidth: CGFloat = 270,
         isMenuActive: Bool = true,
         onMenuHide: @escaping () -> Void,
         toolbarHeight: CGFloat = 44,
         isToolbarActive: Bool = true,
         onToolbarHide: @escaping () -> Void,
         @ViewBuilder menuContent: () -> MenuContent,
         @ViewBuilder toolbarContent: () -> ToolbarContent) {
        
        self.menuWidth = menuWidth
        self.isMenuActive = isMenuActive
        self.onMenuHide = onMenuHide
        self.menuContent = menuContent()
        
        self.toolbarHeight = toolbarHeight
        self.isToolbarActive = isToolbarActive
        self.onToolbarHide = onToolbarHide
        self.toolbarContent = toolbarContent()
    }
    
    var body: some View {
        ZStack {
            GeometryReader { _ in
                EmptyView()
            }
            .background(Color.gray.opacity(0.3))
            .opacity(self.isMenuActive ? 1.0 : 0.0)
            .animation(Animation.easeIn.delay(0.25))
            .onTapGesture {
                self.onMenuHide()
            }
            
            GeometryReader { geometry in
                
                VStack {
                    HStack {
                        
                        Spacer()
                        
                        let space: CGFloat = 0.0 
                        let offset = self.isMenuActive ? space : space + self.menuWidth
                        
                        let toolbarHeight = isToolbarActive ? self.toolbarHeight : 0
                        
                        self.menuContent
                            .frame(width: self.menuWidth, height: geometry.size.height - toolbarHeight, alignment: .center)
                            .background(Color.red)
                            .offset(x: offset)
                            .animation(.default)
                    }
                    
                    let offset = self.isToolbarActive ? 0 : -self.toolbarHeight
                    self.toolbarContent
                        .frame(width: geometry.size.width,
                               height: self.toolbarHeight,
                               alignment: .center)
                        .background(Color.yellow)
                        .offset(y: offset)
                        .animation(.default)
                }
            }
        }
    }
}

struct ControlsOverlayView_Previews: PreviewProvider {
    static var previews: some View {
        ControlsOverlayView(menuWidth: 270,
                            isMenuActive: true,
                            onMenuHide: {},
                            toolbarHeight: 44,
                            isToolbarActive: false,
                            onToolbarHide: {}) {
            Text("Menu Content")
        } toolbarContent: {
            Text("Toolbar Content")
        }

    }
}

The Problem : Given the preview settings, I don't think I should see the toolbar. And yet I do. Attached is a screenshot of the Canvas with the toolbarContent.frame(...) line highlighted in code. You can see that it shows a frame to be drawn offscreen, but the content is not drawn there with it.

I was following from the code to make the side menu slide in/out on the horizontal axis and thought I just need to do essentially the same for the toolbar, but as you can see, that approach doesn't work.

SwiftUI 代码的可视化表示

So I made it work, but I still have no idea why.

Using this new body code, I set the frame of the HStack, and adjusted the offset. Strange is that given the offset value of 'self.toolbarHeight / 2' I don't think it should yield the desired result, and yet it does:

var body: some View {
    ZStack {
        GeometryReader { _ in
            EmptyView()
        }
        .background(Color.gray.opacity(0.3))
        .opacity(self.isMenuActive ? 1.0 : 0.0)
        .animation(Animation.easeIn.delay(0.25))
        .onTapGesture {
            self.onMenuHide()
        }
        
        GeometryReader { geometry in

            VStack {
                
                let toolbarHeight = isToolbarActive ? self.toolbarHeight : 0
                
                
                HStack {
                    Spacer()
                    
                    let space: CGFloat = 0.0 //geometry.size.width - self.menuWidth
                    let offset = self.isMenuActive ? space : space + self.menuWidth

                    self.menuContent
                        .frame(width: self.menuWidth, height: geometry.size.height - toolbarHeight, alignment: .center)
                        .background(Color.red)
                        .offset(x: offset)
                        .animation(.default)
                }
                .frame(width: geometry.size.width,
                       height: geometry.size.height - toolbarHeight,
                       alignment: .center)
                
                // Why does this work?  You'd think it should be self.toolbarHeight without the factor of 2
                let offset = self.isToolbarActive ? 0 : self.toolbarHeight/2 
                
                self.toolbarContent
                    .frame(width: geometry.size.width,
                           height: self.toolbarHeight,
                           alignment: .center)
                    .background(Color.yellow)
                    .offset(y: offset)
                    .animation(.default)
                
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM