I want to customize the tab bar like the curved rectangle in the center but all i am able to do is added one image in the center. the border should come below the circle, tried so many ways but it didn't worked, hope someone would help me to get this.
Here I have tried:
What I am expecting:
TabBarView:
struct TabBarView: View {
@State var selectedTab = 0
var body: some View {
ZStack(alignment: .bottom) {
TabView(selection: $selectedTab) {
HomeView()
.tag(0)
Search()
.tag(1)
Tickets()
.tag(2)
Profile()
.tag(3)
Settings()
.tag(4)
}
RoundedRectangle(cornerRadius: 25)
.frame(width: 350, height: 70)
.foregroundColor(.white)
.shadow(radius: 0.8)
Button {
selectedTab = 2
} label: {
CustomTabItem(imageName: "ticket", title: "Ticket", isActive: (selectedTab == 2))
}
.frame(width: 65, height: 65)
.background(Color.white)
.clipShape(Circle())
.shadow(radius: 0.8)
.offset(y: -50)
HStack {
ForEach(TabbedItems.allCases, id: \.self) { item in
if item != .ticket { // Exclude the center button
Button {
selectedTab = item.rawValue
} label: {
CustomTabItem(imageName: item.iconName, title: item.title, isActive: (selectedTab == item.rawValue))
}
}
}
}
.frame(height: 70)
}
}
}
Extension:
extension TabBarView {
func CustomTabItem(imageName: String, title: String, isActive: Bool) -> some View{
HStack(alignment: .center,spacing: 22){
Spacer()
Image(imageName)
.resizable()
.renderingMode(.template)
.foregroundColor(isActive ? .purple : .gray)
.frame(width: 25, height: 25)
Spacer()
}
}
}
You can do it by creating a Shape
with the required form. I had a go, here's something that's close:
struct TabBarShape: Shape {
let insetRadius: CGFloat
let cornerRadius = CGFloat(25)
let insetCornerAngle = 45.0
func path(in rect: CGRect) -> Path {
var path = Path()
// Start just below the top-left corner
var x = rect.minX
var y = rect.minY + cornerRadius
path.move(to: CGPoint(x: x, y: y))
// Add the rounded corner on the top-left corner
x += cornerRadius
path.addArc(
center: CGPoint(x: x, y: y),
radius: cornerRadius,
startAngle: .degrees(180),
endAngle: .degrees(270),
clockwise: false
)
// Begin inset in middle, cutting into shape
x = rect.midX - (2 * insetRadius)
y = rect.minY + insetRadius
path.addArc(
center: CGPoint(x: x, y: y),
radius: insetRadius,
startAngle: .degrees(270),
endAngle: .degrees(270 + insetCornerAngle),
clockwise: false
)
// Add a half-circle to fit the button
x = rect.midX
y = rect.minY
path.addArc(
center: CGPoint(x: x, y: y),
radius: insetRadius,
startAngle: .degrees(90 + insetCornerAngle),
endAngle: .degrees(90 - insetCornerAngle),
clockwise: true
)
// Complete the inset with the second rounded corner
x += (2 * insetRadius)
y += insetRadius
path.addArc(
center: CGPoint(x: x, y: y),
radius: insetRadius,
startAngle: .degrees(270 - insetCornerAngle),
endAngle: .degrees(270),
clockwise: false
)
// Top-right corner
x = rect.maxX - cornerRadius
y = rect.minY + cornerRadius
path.addArc(
center: CGPoint(x: x, y: y),
radius: cornerRadius,
startAngle: .degrees(270),
endAngle: .degrees(0),
clockwise: false
)
// Bottom-right corner
y = rect.maxY - cornerRadius
path.addArc(
center: CGPoint(x: x, y: y),
radius: cornerRadius,
startAngle: .degrees(0),
endAngle: .degrees(90),
clockwise: false
)
// Bottom-left corner
x = rect.minX + cornerRadius
path.addArc(
center: CGPoint(x: x, y: y),
radius: cornerRadius,
startAngle: .degrees(90),
endAngle: .degrees(180),
clockwise: false
)
path.closeSubpath()
return path
}
}
Then you can use the custom shape in place of the RoundedRectangle
that you were using before:
// RoundedRectangle(cornerRadius: 25)
TabBarShape(insetRadius: 30)
.frame(width: 350, height: 70)
.foregroundColor(.white)
.shadow(color: Color(white: 0.8), radius: 6, x: 0, y: 3)
Button {
selectedTab = 2
} label: {
CustomTabItem(imageName: "ticket", title: "Ticket", isActive: (selectedTab == 2))
}
.frame(width: 50, height: 50)
.background(Color.white)
.clipShape(Circle())
.shadow(radius: 0.8)
.offset(y: -50)
Here's how it looks, you'll probably want to tweak the inset a bit more: