UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Icons in NavigationView Title, Apple Messages style

Forums > SwiftUI

Hi all,

I was wondering if there is a way to embed icons into the NavigationView title bar, inline with the title, the way the stock Messages app has it. I've seen .navigationBarItems(trailing:), but that puts the icons on a line above the title, like in the stock Phone app. My initial idea was passing an HStack to the .navigationBarTitle(title:) modifier and adding the title, a Spacer() and my icon, but that requires that title is a Text, not any View, eliminating that option. Is there a way to replicate the Messages style in SwiftUI?

EDIT: For reference, here is an image of what I'm aiming to achieve, vs what I'm able to achieve.

Thanks a lot, jakcharvat

2      

I have hacked some code together for you. I know that there probably is a way more elegant way of doing this but it works. It does need a lot of tweeking but hopefully it will start you on your way. If anyone can improve on this or show the correct way of doing it, i'd be interested in learning how.

import SwiftUI

struct ContentView: View {
    @State private var midY: CGFloat = 0.0
    @State private var headerText = "Contacts"
    var body: some View {
        NavigationView {
            List {
                HStack {
                    //text
                    HeaderView(headerText: self.headerText, midY: $midY)
                        .frame(height: 40, alignment: .leading)
                        .padding(.top, 5)
                        .offset(x: -45)

                    HStack {
                        //button 1
                        Button(action: {
                            self.action1()
                        }) {
                            Image(systemName: "ellipsis.circle")
                                .font(.largeTitle)
                        }

                        //button 2
                        Button(action: {
                            self.action2()
                        }) {
                            Image(systemName: "pencil.circle")
                                .font(.largeTitle)
                        }
                    }.padding(EdgeInsets(top: 5, leading: 0, bottom: 0, trailing: 16))
                    .foregroundColor(.blue)

                } .frame(height: 40, alignment: .leading)
                    .opacity(self.midY < 70 ? 0.0 : 1.0)
                    .frame(alignment: .bottom)

                ForEach(0..<100){ count in
                    Text("Row \(count)")
                }

            }
            .navigationBarTitle(self.midY < 70 ? Text(self.headerText) : Text(""), displayMode: .inline)
            .navigationBarItems(trailing: self.midY < 70 ? HStack {
                //button 1
                Button(action: {
                    self.action1()
                }) {
                    Image(systemName: "ellipsis.circle")
                    .frame(width: 20, height: 20)
                }

                //button 2
                Button(action: {
                    self.action2()
                }) {
                    Image(systemName: "pencil.circle")
                    .frame(width: 20, height: 20)
                }
            }
            :
                HStack {
                    //button 1
                    Button(action: {
                        self.action1()
                    }) {
                        Image(systemName: "ellipsis.circle")
                        .frame(width: 0, height: 0)
                    }

                    //button 2
                    Button(action: {
                        self.action2()
                    }) {
                        Image(systemName: "pencil.circle")
                        .frame(width: 0, height: 0)

                    }
                }
            )
        }
    }

    func action1() {
        print("do action 1...")
    }

    func action2() {
        print("do action 2...")
    }
}

struct HeaderView: View {
    let headerText: String
    @Binding var midY: CGFloat
    var body: some View {
        GeometryReader { geometry -> Text in
            let frame = geometry.frame(in: CoordinateSpace.global)

            withAnimation(.easeIn(duration: 0.25)) {
                DispatchQueue.main.async {
                   self.midY = frame.midY
                }
            }

            return Text(self.headerText)
                .bold()
                .font(.largeTitle)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

4      

Hi, thanks for the quick reply. Definitely not as clean as I was hoping (I hoped for some out-of-the-box implementation I was missing), but it's definitely a good start. Thank you very much, I'll see if I can improve on it a bit (especially since the Navbar title is sitting under the Navbar itself right now and a few animations).

2      

There is a simpler way by using navigation bar items. That can be leading or trailing the title. Try this and let me know if it worked .navigationBarItems(leading: Image("your image name").resizable().frame(width:40, height:40, alignment: .center).cornerRadius(20))

2      

I maybe late but you could add a center title, image etc:

view.toolbar {
    ToolbarItem(placement: .principal) {
        Text("Title")
    }
}

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.