I would like to change the color of navigationTitle inside NavigationStack.
struct InterestView: View {
var body: some View {
NavigationStack {
VStack {
}
.navigationTitle("interest".uppercased())
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
print("Image tapped!")
} label: {
Text("add".uppercased())
.foregroundColor(Color.primaryColor)
.font(.headline)
}
}
}
}
}
}
I could not find any modifier to change it.
In SwiftUI, you cannot change title color with a simple modifier. You need to change UINavigation Appearance but this will effect globally.
Alternative solution:
You are already using toolbar, so adding title to toolbar is easy as follow. I hope this solves your problem.
struct InterestView: View {
var body: some View {
NavigationStack {
VStack {
}
.toolbar {
ToolbarItemGroup(placement: .principal) {
Text("interest".uppercased())
.foregroundColor(.red)
}
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
print("Image tapped!")
} label: {
Text("add".uppercased())
.foregroundColor(Color.red)
.font(.headline)
}
}
}
}
}
}
Related
I want to have a sticky toolbar that has multiple different filtering options above a List in SwiftUI. Is there a way to just place a full custom view inside the .toolbar property of a List?
With the below code, things look very unexpected
var body: some View {
NavigationView {
List() {
Text("List item")
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
VStack {
Toggle(isOn: $viewModel.isPound) {
Text("test")
}
.toggleStyle(.switch)
Text("A slider to control data")
Text("Another filtering option")
Text("Some random piece of information")
}
}
}
}
}
The NavigationBar is a fixed height for iOS, and is really designed for buttons. You can see the problem (and the space you have to work with) if you add a background colour to it.
struct ContentView: View {
#State private var isPound = false
var body: some View {
NavigationView {
List() {
Text("List item")
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
VStack {
Toggle(isOn: $isPound) {
Text("test")
}
.toggleStyle(.switch)
Text("A slider to control data")
Text("Another filtering option")
Text("Some random piece of information")
}
.border(.red)
}
}
.toolbarBackground(.visible, for: .navigationBar)
.toolbarBackground(.red, for: .navigationBar)
}
}
}
I am making an app where the first view the users see is a home screen with buttons that takes them to a second view. One of the second views present the user with a list of items. When the user clicks on one of these items the user comes to a detailed view of the item. When the user comes to the detailed view he is unfortunately presented with two toolbar buttons in the corner as can be seen here:
.
I know that one of the solutions is to only have one navigationview and that solves my problem. But I need to have toolbar items in my listview to be able to add more items, sort the list and have the list searchable which I'm not able to do without navigationView. I Have tried using scrollView and NavigationStack but it comes out blank.
Does anyone have an idea how to work with mulitple views, not getting double up "back buttons" on the toolbar and still have other toolbar items?
View one: (Home Screen):
NavigationView {
ZStack {
VStack {
Text(title)
.font(.custom("Glacial Indifference", size: 34, relativeTo: .headline).weight(.bold))
.multilineTextAlignment(.leading)
.foregroundColor(.white)
.tracking(10)
.padding(8)
.background(
Rectangle()
.fill(.gray)
.frame(width: 1000, height: 150)
.ignoresSafeArea()
.opacity(0.5))
Spacer()
}
VStack {
NavigationLink {
MapView()
} label: {
Buttons(str: "Cheese Map")
}
.padding(.bottom, 200)
}
VStack {
NavigationLink {
TabView()
} label: {
Buttons(str: "Cheese List")
}
.padding(.bottom, 400)
}
Second View (list):
NavigationView {
List {
ForEach(items, id: \.id) { item in
NavigationLink {
ItemView(item: item)
} label: {
ListItem(item: item)
}
}
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
showingAddItem = true
} label: {
Image(systemName: "plus")
Text("Add Item")
.font(.footnote)
.italic()
}
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu("Sort") {
Picker("Filter Options", selection: $selectedSort) {
ForEach(sortOptions, id: \.self) {
value in
Text(value)
.tag(value)
}
}
}
.onChange(of: selectedSort) { _ in
let sortBy = sorts[sortOptions.firstIndex(of: selectedSort)!]
items.sortDescriptors = sortBy.descriptors
}
}
}
.sheet(isPresented: $showingAddItems) {
AddItemsView(items: Items())
}
.navigationTitle("Item List")
.searchable(text: $searchText)
}
}
}
DetailView:
ScrollView {
ZStack {
VStack {
//More code...
Both .toolbar and .searchable find the nearest enclosing NavigationView automatically. You do not need a NavigationView in your list view.
Here's a self-contained demo. It looks like this:
Here's the code:
import SwiftUI
import PlaygroundSupport
struct HomeScreen: View {
var body: some View {
NavigationView {
List {
NavigationLink("Cheese Map") { Text("Map") }
NavigationLink("Cheese List") { ListView() }
}
.navigationTitle("Home Screen")
}
.navigationViewStyle(.stack)
}
}
struct ListView: View {
#State var items = ["Cheddar", "Swiss", "Edam"]
#State var search: String = ""
var filteredItems: [String] {
return items.filter {
search.isEmpty
|| $0.localizedCaseInsensitiveContains(search)
}
}
var body: some View {
List(filteredItems, id: \.self) {
Text($0)
}
.searchable(text: $search)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
withAnimation {
items.append("Gouda")
}
} label: {
Label("Add Item", systemImage: "plus")
}
.disabled(items.contains("Gouda"))
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu("Sort") {
Button("Ascending") {
withAnimation {
items.sort()
}
}
Button("Descending") {
withAnimation {
items.sort()
items.reverse()
}
}
}
}
}
.navigationTitle("Cheese List")
}
}
PlaygroundPage.current.setLiveView(HomeScreen())
This is a beginner question
I want to move to the next view controller (OptionsView) when the button in the toolbar tapped, how can I do it?
var body: some View {
NavigationView {
VStack{
Text(/*#START_MENU_TOKEN#*/"Hello, World!"/*#END_MENU_TOKEN#*/)
}
.navigationTitle("Profile")
.navigationBarTitleDisplayMode(.inline)
.toolbar{
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
OptionsView()
} label: {
Label("Settings", systemImage: "gear")
}
}
}
}
}
}
You can use the isActive property of a NavigationLink to programmatically activate the link. The NavigationLink can use EmptyView as it's label so that it's hidden, since you only need it to be activated via the Button.
Then, inside of your Button's action, instead of trying to insert the view (which should always be in the view hierarchy -- not inside an action), you can set the the #State variable to activate.
struct ContentView : View {
#State private var optionsActive = false
var body: some View {
NavigationView {
VStack{
Text("Hello, World!")
NavigationLink(isActive: $optionsActive) {
OptionsView()
} label: {
EmptyView()
}
}
.navigationTitle("Profile")
.navigationBarTitleDisplayMode(.inline)
.toolbar{
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
optionsActive = true
} label: {
Label("Settings", systemImage: "gear")
}
}
}
}
}
}
What Im trying to achieve is to have a segmented picker inside the navigation bar, but below the title of the navigation bar while still having the collapse animation.
For example instead of the search, I need a segmented picker:
Uncollapsed
Collapsed
This does not look like that but it could work.
NavigationView {
List {
Text("SwiftUI")
}
.navigationTitle("Title")
.toolbar {
ToolbarItem(placement: .primaryAction) {
VStack {
Picker("", selection: $selectedOption) {
ForEach(options, id:\.hashValue) {option in
Text(option)
}
}
}
}
}
}
If it doesn't need to collapse you can do this.
NavigationView {
VStack {
Picker("", selection: $selectedOption) {
ForEach(options, id:\.hashValue) {option in
Text(option)
}
}
.pickerStyle(SegmentedPickerStyle())
.padding(.horizontal)
List {
ForEach(options, id:\.self) {
searchText in Text(searchText)
}
}
.navigationBarTitle(Text("Select"))
}
}
I don't know how to create an UIToolbar at the bottom of the screen in SwiftUI.
There is no controller in SwiftUI but you can add like this.
var body: some View {
NavigationView {
VStack {
List(model.items) { item in
ItemViewRow(item: item)
}
HStack {
Button(action: {
}) {
Image(systemName: "someimage")
}
Spacer()
Button(action: {
}) {
Image(systemName: "someimage")
}
}.padding()
}
.navigationBarTitle(Text("Items"))
}
}