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.
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)
}
}
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.
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
}