admin管理员组

文章数量:1334668

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 This answer might help: SwiftUI view adding trailing and leading icons – Benzy Neez Commented Nov 20, 2024 at 6:56
  • @BenzyNeez In your custom header example in linked answers, how to deal with case where title is too long? – duckSern1108 Commented Nov 20, 2024 at 7:25
  • @duckSern1108 If the text is long then I would suggest applying some horizontal padding to reserve space for the buttons, like in this answer. If you want the long text to be truncated instead of wrapping then apply .lineLimit(1). – Benzy Neez Commented Nov 20, 2024 at 8:41
  • @BenzyNeez but there will be the case if left View or right View width is too large. I think for this case, it might be better if we use UIView :D – duckSern1108 Commented Nov 20, 2024 at 9:11
  • 1 @duckSern1108 Answer added, which addresses the issue of a long title too. – Benzy Neez Commented Nov 20, 2024 at 10:41
Add a comment  | 

1 Answer 1

Reset to default 2

I 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)

本文标签: