Home > Blockchain >  SwiftUI Pizza Button
SwiftUI Pizza Button

Time:10-23

I wonder if it's possible to create so-called "pizza button", which is per se a round view divided in 4 halfs(buttons) diagonally with one more button in center. Each piece should be clickable

ZStack not working, because only on top button view is clickable. Please give me a suggestion how can i do this.

"pizza button"

My test code: and assets

struct FirstView: View {
    var body: some View {
        VStack {
            HStack {
                Button(action: {
                    
                }, label: {
                    Text("Menu")
                        .frame(width: 88, height: 44)
                        .background(.gray)
                        .cornerRadius(12)
                })
                
                Spacer()
                
                Button(action: {
                    
                }, label: {
                    Text("Settings")
                        .frame(width: 88, height: 44)
                        .background(.gray)
                        .cornerRadius(12)
                })
                
              
            }
            .padding(.horizontal, 40)
            
            ZStack {
    
                Button(action: {
                    print("1")
                }, label: {
                    Image("left_btn")
                        .resizable()
                        .scaledToFit()
                        .border(.green)
                        .frame(width: 215, height: 215)
                        .edgesIgnoringSafeArea(.all)
                })
                
                Button(action: {
                    print("2")
                }, label: {
                    Image("top_btn")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 215, height: 215)
                        .edgesIgnoringSafeArea(.all)
                        .ignoresSafeArea()
                        .border(.yellow)
                })
               

                Button(action: {
                    print("3")
                }, label: {
                    Image("right_btn")
                        .resizable()
                        .frame(width: 215, height: 215)
                        .border(.purple)
                })

                Button(action: {
                    print("4")
                }, label: {
                    Image("bottom_btn")
                        .resizable()
                        .frame(width: 215, height: 215)
                        .border(.blue)
                })
                
                Button(action: {
                    print("5")
                }, label: {
                    Image("center_btn")
                        .resizable()
                        .frame(width: 87, height: 87)
                        .border(.orange)
                })
            }
        }
        .background(.red)
    }
}

left center right [topleft

CodePudding user response:

As discussed in the comments, using assets is not the right way to solve this problem.

I used Arcs to draw Pizza Shapes and SFSymbols for the arrow images.

Here's how it looks like: pizza

Pizza Shapes are responsive, but the small circle is not, but you can easily fix this using GeometryReader

the code:


import SwiftUI

struct ContentView: View {
    @State private var clicked = false
    var body: some View
    {
        ZStack {
            Color.brown.ignoresSafeArea()
            ZStack(alignment: .center) {
                Group {
                    PizzaButton(type: .down)
                        .foregroundColor(clicked ? .teal : .white)
                        .opacity(clicked ? 0.7 : 1)
                        .onTapGesture {
                            print("click")
                            clicked.toggle()
                            
                            DispatchQueue.main.asyncAfter(deadline: .now()   0.2) {
                                clicked = false
                            }
                        }
                    PizzaButton(type: .up)
                    PizzaButton(type: .left)
                    PizzaButton(type: .right)
                }
                .foregroundColor(.white)
                .animation(.interactiveSpring(), value: clicked)
                Circle()
                    .frame(width: 120, height: 120, alignment: .center) // you can use GeometryReader to make these sizes responsive.
                    .foregroundColor(.init(white: 0.98))
                Circle()
                    .strokeBorder(lineWidth: 4)
                    .frame(width: 30, height: 30, alignment: .center)
                    .foregroundColor(.init(white: 0.28))
            }
            .frame(width: 400, height: 400, alignment: .center)
        }
    }
}

struct PizzaButton : View {
    let type : ButtonType
    let alignment : Alignment
    let edge : Edge.Set
    let arrowDirection : String
    
    init (type : ButtonType) {
        self.type = type
        switch (type) {
        case .up:
            alignment = .top
            edge = .top
            arrowDirection = "up"
        case .right:
            alignment = .trailing
            edge = .trailing
            arrowDirection = "forward"
        case .left:
            alignment = .leading
            edge = .leading
            arrowDirection = "backward"
        case .down:
            alignment = .bottom
            edge = .bottom
            arrowDirection = "down"
        }
    }
    var body: some View {
        GeometryReader { geo in
            ZStack(alignment: alignment) {
                PizzaButtonShape(type: type)
                    .stroke(lineWidth: 1)
                    .background(PizzaButtonShape(type: type)) // this is required because .stroke clears the shapes background.
                Image(systemName: "arrow.\(arrowDirection)")
                    .foregroundColor(.init(white: 0.35))
                    .font(.largeTitle)
                    .padding(edge, geo.size.width / 5)
            }
        }
    }
}

struct PizzaButtonShape : Shape {
    let type : ButtonType
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let startAngle : Angle
        let endAngle : Angle
        
        switch(type) {
        case .up:
            startAngle = .degrees(225)
            endAngle = .degrees(315)
            break
        case .down:
            startAngle = .degrees(45)
            endAngle = .degrees(135)
            break
        case .right:
            startAngle = .degrees(315)
            endAngle = .degrees(45)
            break
        case .left:
            startAngle = .degrees(135)
            endAngle = .degrees(225)
            break
        }
        
        path.move(to: CGPoint(x: rect.midX, y: rect.midY))
        
        path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.height / 3, startAngle: startAngle, endAngle: endAngle, clockwise: false)
        
        return path
    }
}

enum ButtonType {
    case left, right, up, down
}
  • Related