I am developing an App that supports multiple Profiles. I really like the way Apple displays the Profile Icon
next to the Large Navigation Bar Title
in all their Apps. See the Screenshot below:
My Question is the following:
SwiftUI
? And if so, how?SwiftUI
, how can I achieve it including UIKit
Code?Thanks for your help.
I solved this by using SwiftUI-Introspect , to "Introspect underlying UIKit components from SwiftUI".
Here is an example of a view:
struct ContentView: View {
@State private var lastHostingView: UIView!
var body: some View {
NavigationView {
ScrollView {
ForEach(1 ... 50, id: \.self) { index in
Text("Index: \(index)")
}
.frame(maxWidth: .infinity)
}
.navigationTitle("Large title")
.introspectNavigationController { navController in
let bar = navController.navigationBar
let hosting = UIHostingController(rootView: BarContent())
guard let hostingView = hosting.view else { return }
// bar.addSubview(hostingView) // <--- OPTION 1
// bar.subviews.first(where: \.clipsToBounds)?.addSubview(hostingView) // <--- OPTION 2
hostingView.backgroundColor = .clear
lastHostingView?.removeFromSuperview()
lastHostingView = hostingView
hostingView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingView.trailingAnchor.constraint(equalTo: bar.trailingAnchor),
hostingView.bottomAnchor.constraint(equalTo: bar.bottomAnchor, constant: -8)
])
}
}
}
}
Bar content & profile picture views:
struct BarContent: View {
var body: some View {
Button {
print("Profile tapped")
} label: {
ProfilePicture()
}
}
}
struct ProfilePicture: View {
var body: some View {
Circle()
.fill(
LinearGradient(
gradient: Gradient(colors: [.red, .blue]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.frame(width: 40, height: 40)
.padding(.horizontal)
}
}
The .frame(width: 40, height: 40)
& hostingView.bottomAnchor
constant
will need to be adjusted to your needs.
And the results for each option (commented in the code):
I done this with pure SwiftUI. You have to replace the Image("Profile")
line with your own image (maybe from Assets or from base64 data with UIImage).
HStack {
Text("Apps")
.font(.largeTitle)
.fontWeight(.bold)
Spacer()
Image("Profile")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.clipShape(Circle())
}
.padding(.all, 30)
This products following result:
Let's assume that you have NavigationView
and inside that there's only ScrollView
and .navigationTitle
. You can add that profile image there by using overlay.
NavigationView {
ScrollView {
//your content here
}
.overlay(
ProfileView()
.padding(.trailing, 20)
.offset(x: 0, y: -50)
, alignment: .topTrailing)
.navigationTitle(Text("Apps"))
}
Where ProfileView could be something like this:
struct ProfileView: View {
var body: some View {
Image("Profile")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.clipShape(Circle())
}
}
The result will be like this...
...which is pretty close to the App Store:
Here is a possible solution. I added an HStack
view which contains title and image as a navigationBarItems
struct ContentView: View {
var body: some View {
GeometryReader { geo in
NavigationView{
VStack{
ScrollView{
Text("Contents")
Spacer()
Text("Contents2")
Spacer()
Text("Contents3")
}
}.navigationBarItems(leading: HStack {
Text("Apps")
.font(.largeTitle)
.fontWeight(.bold)
Spacer().frame(width: geo.size.width * 0.6)
Image(systemName: "person.crop.circle")
.resizable()
.frame(width: 40, height: 40)
})
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.