ios – SwiftUI align customized subviews

0
13
ios – SwiftUI align customized subviews


You do not want any GeometryReaders to realize this structure. You are able to do it merely with some overlays and orientation-based stacks.

For the buttons to be aligned with the blue digicam preview, they only have to be in the identical stack. The one distinction is whether or not it is an HStack or a VStack primarily based on orientation.

Within the instance beneath, I stored it easy by checking the verticalSizeClass, but it surely may be finished utilizing ViewThatFits possibly, though it might turn into unnecessarily difficult.

The buttons are additionally equally organized in a horizontal or vertical stack primarily based on orientation. If wanted, their container may very well be a ScrollView to accommodate extra buttons.

Relying on the orientation, it’s worthwhile to ignore the suitable secure areas, so the digicam preview can fill the area properly.

Extra parts may be added over the blue preview as overlays (see the grid strains and the shut button as examples within the code beneath).

import SwiftUI

struct CameraUIRootView: View {

    //State values
    @State non-public var showCameraPreview = false
    
    //Physique
    var physique: some View {
        
        VStack {
            Button {
                withAnimation {
                    showCameraPreview.toggle()
                }
            } label: {
                Label("Take image", systemImage: "digicam.fill")
            }
            .buttonStyle(.borderedProminent)
        }
        .fullScreenCover(isPresented: $showCameraPreview) {
            CameraUIPreview()
        }
    }
}

struct CameraUIPreview: View {
    
    //Atmosphere values
    @Atmosphere(.verticalSizeClass) var verticalSizeClass
    @Atmosphere(.dismiss) var dismiss
    
    //Helper computed property for detecting panorama orientation
    non-public var isLandscapeOrientation: Bool {
        verticalSizeClass == .compact
    }
    
    //State values
    @State non-public var showGridLines = false

    //Physique
    var physique: some View {
        
        Group {
            if isLandscapeOrientation {
                HStack(spacing: 0) {
                    //Digital camera preview
                    cameraPreview
                    
                    //Controls
                    CameraUIControls()
                }
            }
            else {
                VStack(spacing: 0) {
                    //Digital camera preview
                    cameraPreview
                    
                    //Controls
                    CameraUIControls()
                }
            }
        }
        .ignoresSafeArea(.container, edges: isLandscapeOrientation ? [.leading, .vertical] : [.top]) // <- Elective: use [.bottom] when you do not wish to push the preview into the highest secure space or go away clean [], which can trigger points with respecing the side ratio relying on machine
        .persistentSystemOverlays(.hidden)
        .statusBarHidden()
        .body(maxWidth: .infinity, maxHeight: .infinity,  alignment: isLandscapeOrientation ? .main : .prime)

    }
    
    non-public var cameraPreview: some View {
        
        Colour.blue
            .aspectRatio(isLandscapeOrientation ? 16.0/9.0 : 9.0/16.0, contentMode: .match)
    
            //Shut preview button
            .overlay(alignment: .topTrailing) {
                Button {
                    withAnimation {
                        // showCameraPreview.toggle()
                        dismiss()
                    }
                } label: {
                    Textual content("Shut")
                }
                .tint(.white)
                .padding(30)
            }
        
            // Shutter button
            .overlay(alignment: isLandscapeOrientation ? .trailing : .backside) {
                Button {
                    showGridLines.toggle()
                } label: {
                    Picture(systemName: "digicam")
                        .imageScale(.massive)
                        .padding()
                }
                .tint(.white)
                .body(width: 80, peak: 80)
                .background(.white.gradient.opacity(0.4), in: Circle())
                .padding()
            }
        
            //Gridlines overlay
            .overlay {
                CameraUIGridLines()
            }
    }
}

struct CameraUIControls: View {
    
    //Atmosphere values
    @Atmosphere(.verticalSizeClass) var verticalSizeClass
    
    //Helper computed property for detecting panorama orientation
    non-public var isLandscapeOrientation: Bool {
        verticalSizeClass == .compact
    }
    
    //Physique
    var physique: some View {
        
        Group {
            if isLandscapeOrientation {
                VStack {
                    controls
                }
            }
            else {
                HStack {
                    controls
                }
            }
        }
        .padding()
    }
    
    @ViewBuilder
    non-public var controls: some View {
        
        Group {
            
            //Flash button
            Button {
                //...
            } label: {
                Picture(systemName: "bolt.fill")
                    .padding()
            }
            
            Spacer()
            
            //Gridlines button
            Button {
                //...
            } label: {
                Picture(systemName: "grid")
                    .padding()
            }
            
            Spacer()
            
            //Macro mode button
            Button {
                //...
            } label: {
                Picture(systemName: "digicam.macro")
                    .padding()
            }
            
            Spacer()
            
            //Metering mode button
            Button {
                //...
            } label: {
                Picture(systemName: "digicam.metering.heart.weighted")
                    .padding()
            }
            
            Spacer()
            
            //Flip digicam button
            Button {
                //...
            } label: {
                Picture(systemName: "digicam.rotate")
                    .padding()
            }
        }
        .background(.grey.gradient.opacity(0.2), in: Circle())
        .tint(.major)
    }
}

struct CameraUIGridLines: View {
    
    //Physique
    var physique: some View {
        
        ZStack {
            HStack {
                gridLines
            }
            VStack {
                gridLines
            }
        }
    }
    
    non-public var gridLines: some View {
        Group {
            Spacer()
            divider
            Spacer()
            divider
            Spacer()
        }
    }
    
    non-public var divider: some View {
        Divider()
            .background(Colour.white) //Divider colour
    }
}


//Preview
#Preview("Root view") {
    CameraUIRootView()
}

#Preview("Digital camera preview") {
    CameraUIPreview()
}

#Preview("Controls") {
    CameraUIControls()
}

enter image description here

LEAVE A REPLY

Please enter your comment!
Please enter your name here