Add View in navigationBarTitle - SwiftUI - ios

I am able to add Title using .navigationBarTitle(Text((msgDetails.name))) But i wanted to add subtitle under the title in the navigationbar. Looks like title will not accept the View and it accepts only Text. I tried \n in the title but it is not working. IS there any way i can add the subtitle in navigation bar. I used leading and trailing to add left and right button in the navigation bar. I wanted to show title and subtitle along with this left and right button
Navigation Bar

If you look in SwiftUI documentation you'll see only a few overloads of navigationBarTitle function. All of them requires special parameters, like Text or StringProtocol. So you can't just put some View into navigation bar.
I can propose one strange, but working version. It's about using .navigationBarItems(leading:... - it requires some view, which you can customize (within reason). Here is simple example:
struct ContentView: View {
var body: some View {
NavigationView {
Text("Main view")
.navigationBarItems(leading:
HStack {
Button(action: {}) {
Image(systemName: "return")
}
VStack {
Text("Title")
.bold()
.font(.system(size: 30))
Text("Subtitle")
.italic()
.font(.system(size: 15))
}
.padding(.horizontal, 100) // mb it's better to use GeometryReader for centering
})
}
}
}
and you'll achieve something like this:

Related

Adjust View up with Keyboard show in SwiftUI 3.0 iOS15

I have sign up page with a VStack embedded in a ScrollView that's embedded in a VStack. In the innermost VStack I have a series of TextFields with a custom TextFieldStyle.
The UI of the signup page looks like this:
VStack {
ScrollView {
VStack(spacing: 24) {
TextField(text: $firstNameText) {
Text(.firstNameLabel)
}
.textFieldStyle(.customTextfieldStyle())
TextField(text: $lastNameText) {
Text(.lastNameLabel)
}
.textFieldStyle(.customTextfieldStyle())
}
}
Spacer()
Button(action: submit) {
Text(.nextButtonTitle)
}
}
Next, the customTextfieldStyle looks like this:
VStack(alignment: .leading, spacing: 0) {
configuration
.font(.bodyBook14)
.padding(.bottom, 16)
Rectangle()
.fill(errors.isEmpty ? Color.primary : .errorRed)
.frame(height: 1)
ForEach(errors) { error in
Text(error.title)
.font(.bodyBook14)
.foregroundColor(.errorRed)
.padding(.top, 8)
}
}
In my custom textfield style I added a rectangle and an error text. The problem I'm having is with this custom style, the rectangle and error messages below the textfield is being covered on focus. the keyboard avoidance doesn't offset enough of the scrollview to display them to the user. The keyboard properly offsets the view just enough to show only the textfield but not the rectangle and error messages. Is it possible to make the keyboard recognize the entire custom textfield style should shift up?
Screenshot below shows how error text is all covered by the keyboard / button.

SwiftUI TextEditor View content is hidden behind Navigation Bar

I'm working on a SwiftUI View with a NavigationBar. The view is very simple, it's a full-page TextEditor:
struct NotesEditingScreen: View {
#State var text: String
var body: some View {
TextEditor(text: $text)
.padding(.horizontal)
.navigationBarTitle("Editing")
}
}
The issue I'm seeing, is that when landing on this screen (via a NavigationLink) the top of the TextEditor is covered up by Navigation Bar:
My desired behavior is that the TextEditor content appears beneath the Navigation Bar, like it appears after you manually scroll to the top to reveal the text.
Is there a solution/workaround to this issue? I was hoping for either some offset, a setting on NavigationBar, or some programmatic scroll behavior that could be done onAppear. Any suggestions welcome.
I think it's an unexpected behavior.
You can try this:
GeometryReader { geo in
ScrollView {
TextEditor(text: $text)
.frame(height: geo.size.height)
}
}

Stick button at bottom when keyboard appears

I'm making a screen when I ask the user his name and a Button to the bottom of the page.
My problem is, when I'm focusing the Textfield, the keyboard appears but push up the button. How can I stick my button to the bottom of my view and be hidden by the keyboard ?
Before the keyboard appears:
When the keyboard showed up:
Thanks a lot !
You can use .ignoresSafeArea(.keyboard) modifier:
struct ContentView: View {
#State var text = "Test"
var body: some View{
VStack {
Text("Hello, world")
Spacer()
TextField("", text: $text)
Spacer()
Button("Submit") {}
}.ignoresSafeArea(.keyboard)
}
}
This has to be applied to the surrounding parent stack -- applying it to the Button element alone in the above example has no effect.

SwiftUI disable keyboard avoidance for custom tabbar control

I made a custom tabbar because the system one is not customizable in pure swiftUI.
The custom tab view looks like this:
struct MainTabView: View {
var body: some View {
VStack(spacing: 0) {
switch router.currentTab {
case .tab1:
Tab1View()
case .tab2:
Tab2View()
...
}
Spacer()
HStack(spacing: 0) {
TabBarIconView(viewRouter: viewRouter, ...)
TabBarIconView(viewRouter: viewRouter, ...)
TabBarIconView(viewRouter: viewRouter, ...)
TabBarIconView(viewRouter: viewRouter, ...)
TabBarIconView(viewRouter: viewRouter, ...)
}
//.ignoresSafeArea(.keyboard) // second try
}
}
//.ignoresSafeArea(.keyboard) // first try
}
When I use a textfied in one of the TabXViews, the bottom HStack stays above the keyboard.
A solution I found is to disable keyboard avoidance for the tabbar. I made this by uncommenting the above line .ignoresSafeArea(.keyboard) (first try)
But of course, this apply globaly, for each subview => If I declare a scrollview, the bottom won't be accessible when keyboard is open.
I tryed to set the .ignoresSafeArea(.keyboard) under the above HStack (second try), but this doesn't do anything (HStack stays above the keyboard)
Is there a solution to opt-in keyboard avoidance again in subviews?

Avoid button styling its content in SwiftUI

I'm creating an iOS app using Apple's SwiftUI framework. As I need to detect if the user taps on a specific area of the screen, I obviously use a button.
The problem is that the area contains an Image and a Text, and as the button automatically gives its content the blue color, the image is also colored, so instead of being an Image it's just a blue rounded rectangle.
It is said that an image is worth a thousand words, and as I'm not good at explaining, here you have a graphic demonstration of what happens:
Outside the button (without button styling)
Inside the button (with button styling)
This happens because the button is adding .foregroundColor(.blue) to the image.
How can I avoid/disable the button adding style to its components?
EDIT: This is my button code:
ContentView.swift:
Button(action: {/* other code */}) {
PackageManagerRow(packageManager: packageManagersData[0])
}
PackageManagerRow.swift:
struct PackageManagerRow : View {
var packageManager : PackageManager
var body: some View {
VStack {
HStack {
Image(packageManager.imageName)
.resizable()
.frame(width: 42.0, height: 42.0)
Text(verbatim: packageManager.name)
Spacer()
Image(systemName: "checkmark")
.foregroundColor(.blue)
.opacity(0)
}.padding(.bottom, 0)
Divider()
.padding(.top, -3)
}
}
}
I think this is from the rendering mode for the image you are using.
Where you have Image("Cydia logo") (or whatever).
You should be setting the rendering mode like...
Image("Cydia Logo").renderingMode(.original)
You can also add a PlainButtonStyle() to your button to avoid iOS style behaviors.
Something like that with your example :
Button(action: {/* other code */}) {
PackageManagerRow(packageManager: packageManagersData[0])
}.buttonStyle(PlainButtonStyle())
I hope it will help you!
Another option is to not use a Button wrapper, but instead use tapAction directly on the Image to trigger your action when the image is pressed
HStack {
Button(action: {
print("Tapped")
}, label: {
Image("Logo").renderingMode(.original) // Add Rendering Mode
})
Text("Cydia")
}
A button with an icon! How original 😀.
If you are dealing with SF symbols then the following will do fine:
Button(action: addItem) {
Text(Image(systemName: "plus").renderingMode(.original))
+
Text("This is Plus")
}
.font(.system(size: 42))
The limitation of the option above is you don't have control over Image's size. So for custom images the following is more appropriate:
Button(action: addItem) {
Label(
title: { Text("Label").font(.system(size: 40)) }, // Any font you like
icon: { Image(systemName: "rectangle.and.pencil.and.ellipsis") // Both custom and system images, i.e. `Image("Cydia logo")`
.renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 42, height: 42) // Any size you like
.padding() // Any padding you need
} // and etc.
)
}
Apply the style .plain to your button to avoid overlay color.
// Before
Button(...)
// After
Button(...)
.buttonStyle(.plain) // Remove the overlay color (blue) for images inside Button
.plain button style, that doesn’t style or decorate its content while idle, but may apply a visual effect to indicate the pressed, focused, or enabled state of the button.
Another solution is to custom the style with ButtonStyle
like: struct MyButtonStyle:ButtonStyle { }
You have to render the original image by adding .renderingMode(.original) right after your image declaration.
Image("your_image_name")
.renderingMode(.original)

Resources