SwiftUI: Change navigation bar title in the more tab? - swiftui

I am begining to get my haead around swiftUI. So I have a simple tabView inside a Navigation View as below.
import SwiftUI
struct BasicView: View {
var climbList: [ClimbDetail]
var body: some View {
NavigationView{
VStack{
Text("").navigationBarTitle("Climbers Log", displayMode:.inline)
TabView {
Text("Search").tabItem{
Image(systemName:"magnifyingglass")
Text("Search")
}
Text("Stats").tabItem{
Image(systemName:"list.dash")
Text("Stats")
}
ClimbList(climbs: climbList).tabItem{
Image(systemName: "square")
Text("Climbs")
}
Text("Log").tabItem{
Image(systemName:"square.and.pencil")
Text("Log")
}
Text("Profile").tabItem{
Image(systemName:"person.circle")
Text("Profile")
}
Text("Settings").tabItem{
Image(systemName:"gear")
Text("Settings")
}
Text("Add Climb").tabItem{
Image(systemName:"plus")
Text("Add Climb")
}
}
}
}
}
}
Genrally it works as expected, however as I have 7 tabs it defults to the 'More' tab for the 5th tab. This is fine and good for the user.
However my issue is when you click the 'More' tab you get the a title bar and edit button with 'More' as the title. Which appears below the title bar I have set above.
So my question is how can I hide my titleBar when the user is on the 'More' tab and only show it inside the other tabs?

First off all, thanks for the question. I didn't know Apple provides More page by default for too long TabBars. I always needed that.
Back to you question, you just need to rearrange things. First off all, make the TabBar top level. Then a NavigationView and here comes your content. Later on you might outsource every view, to an own file.
TabView {
NavigationView
{
VStack
{
Text("Search")
}
.navigationBarTitle("Climbers Log", displayMode:.inline)
}.tabItem {
Image(systemName:"magnifyingglass")
Text("Search")
}
Every view takes it own NavigationView.. and then it works.

Related

SwiftUI - How to make navigation bar title editable (without changing any other behavior)?

I really like the look of the navigation bar title in SwiftUI, and I like that it appears just below the safe area, but appears in the principal part of the toolbar when you scroll down. I'm wondering how to completely replicate this look and behavior but make it editable by the user (most likely through a textfield?)
I've tried
.toolbar {
ToolbarItem(placement: .principal) {
TextField("Navigation Title", text: $mainTitle)
}
}
But this simply places the title in the toolbar at all times, rather than only when you scroll slightly.
Any ideas?
First I explain why your code does not work:
Only the size of the navigationTitle changes when you start to scroll, not the size of the whole toolbar or its items.
But I think I have a solution:
import SwiftUI
struct ContentView: View {
#State private var title: String = "Title"
#State private var titleSmall: Bool = false
var body: some View {
NavigationView {
List {
GeometryReader { geo in
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
.onChange(of: geo.frame(in: .global).minY) { val in
if val <= 53.5 {
titleSmall = true
} else {
titleSmall = false
}
}
}
Text("Hello, world!")
}
.toolbar {
ToolbarItem(placement: .principal) {
TextField("Title", text: $title)
.multilineTextAlignment(.center)
.font(titleSmall ? .headline : .largeTitle.bold())
.accessibilityAddTraits(.isHeader)
}
}
}
}
}
What the code does is: It gets the top Y position from the first (in this example) list item.
Then it checks if the first list item is under the title bar and changes the font size of the title if necessary.
The only Problem I see is that there is a pretty rough transition between small and big title but I think you can figure out how to fix this.
If you have more questions how the code works just ask
I hope that solves your question.
And I would recommend to have a look at Paul Hudson’s video about the Geometry Reader (he’s a great YouTuber): https://youtu.be/kh9lnIYgW1E
I just realized that it says „OLD“ in the video title, so it may be outdated.
But he has some other videos about the Geometry Reader.
just search for „Paul Hudson Geometry Reader“

SwiftUI TabView More tab crashes first press

var body: some View {
TabView {
ScheduleView().tabItem {
Image(systemName: "calendar")
Text("Schedule")
}.tag(tbScheduleTag)
DutyBookView().tabItem {
Image(systemName: "books.vertical")
Text(dutyBookViewTabText)
}.tag(tbDutyBookTag)
TimetableView().tabItem {
Image(systemName: "calendar.badge.clock")
Text("Timetable")
}.tag(tbTimetableTag)
**... plus 7 other Tabs removed for post readability**
}
}
My TabView creates 10 Tabs so I automatically get the "More" TabItem. After App launches and I press that More tab before anything else the Tab crashes back to the Initial tab. If I tap any other tab first or the More tab again it loads fine. See attached for demo. The first time selected it crashes back the second time it works.
Anyone suggestions please?
I added #State variable and set it to selection attribute of TabView. To make this work I replaced your tags with new enum values.
struct ContentView: View {
enum Tab {
case schedule, dutyBook, timetable, locateTrain, settings
case tfLRestricted, subscription, serviceStatus, info, storedDuties
}
#State var tab: Tab = .schedule
var body: some View {
TabView(selection: self.$tab) { //this is the solution
ScheduleView().tabItem {
Image(systemName: "calendar")
Text("Schedule")
}.tag(Tab.schedule)
DutyBookView().tabItem {
Image(systemName: "books.vertical")
Text(dutyBookViewTabText)
}.tag(Tab.dutyBook)
// ...
}
}
}

Rename Cancel button on a modal sheet

I currently invoke an Example Sentence modal sheet by toggling $showingModal on a certain condition.
.sheet(isPresented: $showingModal) {
ExampleSentence()
}
According to the Human Interface Guidelines, I am able to rename Cancel to something more appropriate such as Dismiss. If I was using UIKit instead of SwiftUI, I'd be using the presentController function which then explains that I can rename the Cancel button using setTitle. https://developer.apple.com/documentation/watchkit/wkinterfacecontroller/1619560-presentcontroller
But if I'm using SwiftUI, is it possible to rename the Cancel button?
EDIT: Sorry I should have clarified that this is a watchOS app. By default it creates a Cancel button in the top left corner but I just want to rename it to dismiss.
You can do that by using a NavigationView within your ExampleSentences view and adding a toolbar to it, something like this.
struct ExampleSentence: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack {
Text("Hello View")
}
.navigationBarTitle("Example Sentences")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Done")
}
}
}
}
}
}

Handling focus event changes on tvOS in SwiftUI

How do I respond to focus events on tvOS in SwiftUI?
I have the following SwiftUI view:
struct MyView: View {
var body: some View {
VStack {
Button(action: {
print("Button 1 pressed")
}) {
Text("Button 1")
}.focusable(true) { focused in
print("Button 1 focused: \(focused)")
}
Button(action: {
print("Button 2 pressed")
}) {
Text("Button 2")
}.focusable(true) { focused in
print("Button 2 focused: \(focused)")
}
}
}
Clicking either of the buttons prints out correctly. However, changing focus between the two buttons does not print anything.
This guy is doing the same thing with rows in a list & says it started working for him with the Xcode 11 GM, but I'm on 11.5 and it's definitely not working (at least not for Buttons (or Toggles - I tried those too)).
Reading the documentation, this appears to be the correct way to go about this, but it doesn't seem to actually work. Am I missing something, or is this just broken?
In case anybody else stumbles upon this question, the answer is to make your view data-focused
So, if you have a list of movies in a scrollview, you would add this to your outer view:
var myMovieList: [Movie];
#FocusState var selectedMovie: Int?;
And then somewhere in your body property:
ForEach(0..<myMovieList.count) { index in
MovieCard(myMovieList[i])
.focusable(true)
.focused($selectedMovie, equals: index)
}
.focusable() tells the OS that this element is focusable, and .focused tells it to make that view focused when the binding variable ($selected) equals the value passed to equals: ...
For example on tvOS, if you wrap this in a scrollview and press left/right, it will change the selection and update the selected index in the $selectedMovie variable; you can then use that to index into your movie list to display extra info.
Here is a more complete example that will also scale the selected view:
https://pastebin.com/jejwYxMU

SwiftUI Navigation Bar Title doesn't appear

I'm not sure if anything changed in Beta 3, however, when trying to add the NavigationBarTitle modifier to NavigationView, it does not show the text for the title? Any ideas?
NavigationView {
List(0 ..< 20) { item in
NavigationLink(destination: Text("1")) {
Text("Navigate 1")
}
}
}.navigationBarTitle(Text("Update")).navigationBarHidden(false)
}
The list shows but no title for the list in the NavigationView
You're setting .navigationBarTitle and .navigationBarHidden on NavigationView when they should be modifiers on List instead:
NavigationView {
List(0..<20) { item in
NavigationLink(destination: Text("1")) {
Text("Navigate 1")
}
}
.navigationBarTitle("Update")
.navigationBarHidden(false)
}
You can also just remove .navigationBarHidden(false) (unless you're setting it to true in a previous view or something).
Your code works fine and the navigationBarTitle is not outdated. It must be placed above (inside the Navigation View). Yes, it is sometimes confusing, it is necessary to remember this.
To the place where you currently have it .navigationBarTitle(Text ("Update")).navigationBarHidden(false) you need to set the modifier .navigationViewStyle(StackNavigationViewStyle ()), which means that you should always show the first screen regardless of the screen size.
var body: some View {
NavigationView {
List(0 ..< 20) { item in
NavigationLink(destination: Text("1")) {
Text("Navigate 1")
}
}
.navigationBarTitle(Text("Update"), displayMode: .automatic).navigationBarHidden(false)
}
// that means only show one view at a time no matter what device I'm working
.navigationViewStyle(StackNavigationViewStyle())
}