I'm trying to create a Navbar that has a leading and trailing view and my title at center or left aligned.
At the beginning I was trying to do so with a simple HStack:
Hstack{
leading()
.frame(alignment: .leading)
Spacer()
title()
Spacer()
trailing()
.frame(alignment: .trailing)
}
The problem here is that the leading and trailing they are: 1 - Optional, some cases only the lading can be present and no trailing 2 - Different widths leading can be bigger than trailing and vice versa
So it can cause the issue where the title is not correctly center aligned.
So what I tried was the following:
@State var widthNavigation: CGFloat = 0.00
@State var widthActions: CGFloat = 0.00
@State var titleWidth: CGFloat = 0.00
@State var totalWidth: CGFloat = 0.00
public var body: some View {
HStack(alignment: .center, spacing: 0) {
navigationIcon()
.background(GeometryReader { geoNav in
Color.clear.onAppear { self.widthNavigation = geoNav.size.width }
})
title()
.background(GeometryReader { geoTitle in
Color
.clear
.onAppear {
titleWidth = geoTitle.size.width
}
}
)
.offset(
x: totalWidth/2 - titleWidth/2
)
actions()
.background(GeometryReader { geoAct in
Color.clear.onAppear { self.widthActions = geoAct.size.width }
})
}
.background(
GeometryReader { geometry in
Color.clear.onAppear { self.totalWidth = geometry.size.width }
}
)
.frame(maxWidth: .infinity)
.padding(.horizontal, 8)
}
Basically this code get the width of the views and tries to infer an offset to the title. (I've tried many different offset logic but still
This is what I need to achieve:
This is my result in general:
I'm trying to create a Navbar that has a leading and trailing view and my title at center or left aligned.
At the beginning I was trying to do so with a simple HStack:
Hstack{
leading()
.frame(alignment: .leading)
Spacer()
title()
Spacer()
trailing()
.frame(alignment: .trailing)
}
The problem here is that the leading and trailing they are: 1 - Optional, some cases only the lading can be present and no trailing 2 - Different widths leading can be bigger than trailing and vice versa
So it can cause the issue where the title is not correctly center aligned.
So what I tried was the following:
@State var widthNavigation: CGFloat = 0.00
@State var widthActions: CGFloat = 0.00
@State var titleWidth: CGFloat = 0.00
@State var totalWidth: CGFloat = 0.00
public var body: some View {
HStack(alignment: .center, spacing: 0) {
navigationIcon()
.background(GeometryReader { geoNav in
Color.clear.onAppear { self.widthNavigation = geoNav.size.width }
})
title()
.background(GeometryReader { geoTitle in
Color
.clear
.onAppear {
titleWidth = geoTitle.size.width
}
}
)
.offset(
x: totalWidth/2 - titleWidth/2
)
actions()
.background(GeometryReader { geoAct in
Color.clear.onAppear { self.widthActions = geoAct.size.width }
})
}
.background(
GeometryReader { geometry in
Color.clear.onAppear { self.totalWidth = geometry.size.width }
}
)
.frame(maxWidth: .infinity)
.padding(.horizontal, 8)
}
Basically this code get the width of the views and tries to infer an offset to the title. (I've tried many different offset logic but still
This is what I need to achieve:
This is my result in general:
Share Improve this question edited Nov 20, 2024 at 10:13 Benzy Neez 22.6k3 gold badges15 silver badges43 bronze badges asked Nov 20, 2024 at 6:23 José CaiqueJosé Caique 111 silver badge1 bronze badge 5 |1 Answer
Reset to default 2I would suggest splitting the buttons and the title into two layers, so that the title is independent of the buttons.
A ZStack
can be used to combine the two layers:
ZStack {
HStack {
navigationIcon()
Spacer()
actions()
}
title()
}
.padding(.horizontal, 8)
If there is any risk that the title may be long and overlap with one of the icon groups, then you could reserve space for the buttons using hidden copies. Since you don't know which group will be the widest, you can use another ZStack
to build the footprint:
private var footprintForIcons: some View {
ZStack {
navigationIcon()
actions()
}
.disabled(true)
.hidden()
}
This is then used as followss:
ZStack {
HStack {
navigationIcon()
Spacer()
actions()
}
HStack {
footprintForIcons
title()
footprintForIcons
}
}
.padding(.horizontal, 8)
custom header
example in linked answers, how to deal with case where title is too long? – duckSern1108 Commented Nov 20, 2024 at 7:25.lineLimit(1)
. – Benzy Neez Commented Nov 20, 2024 at 8:41left View
orright View
width is too large. I think for this case, it might be better if we useUIView
:D – duckSern1108 Commented Nov 20, 2024 at 9:11