Add Button with Image and Text in ToolbarItem SwiftUI - ios

I want button exactly as in Reminders app in iOS
Below code note working, I also tried using label and system image name.
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(action: {}, label: {
HStack {
Image(systemName: "plus.circle.fill")
Text("New Reminder")
}
})
}
}

Create a custom label style
struct VerticalLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
VStack {
configuration.icon.font(.headline)
configuration.title.font(.footnote)
}
}
}
Then you can you use the custom style for your label
Button(action: {}, label: {
Label("Home", systemImage: "house")
.labelStyle(VerticalLabelStyle())
})

Related

SwiftUI Xcode 12.3 can't change button size in toolbar

struct ContentView: View {
var body: some View {
NavigationView {
List {
Text("Hi")
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Text("Title")
.font(.headline)
}
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {}) {
Image(systemName: "person.circle")
.font(.largeTitle)
}
}
}
}
}
}
The .font(.largeTitle) on Image has no effect, only if I use it inside a button.
Is this a bug or am I doing something wrong?
It looks like SwiftUI treats single toolbar items differently (applies their own style, size etc).
A possible workaround is to put a Button in a more complex view, as in: How to change color of ToolbarItem with navigationBarLeading placement in SwiftUI
Adapted to your example it can look like this:
ToolbarItem(placement: .navigationBarLeading) {
HStack {
Button(action: {}) {
Image(systemName: "person.circle")
.font(.largeTitle)
}
Text("")
}
}

replace Tabbar with toolbar in SwiiftUI 2.0

I'm trying replicate the behavior of iOS Photos app.
Till now the thing I can't figure how could be done is the select mode, where when I press the button select how I can change the bottom bar?
Graphically, what I intend is, in this view:
When I pressed the button, the bottom bar changes to:
In the real project the views are embed inside a NavigationView
The code of the main view is similar to
struct ContentView: View {
var body: some View {
NavigationView{
TabView{
data()
.tabItem {
Text("Data")
}
data2()
.tabItem {
Text("Data")
}
}
}
}
I'm using Xcode 12 and swiftUI 2.0
First we need Conditional modifier like that https://stackoverflow.com/a/61253769/2715636
struct conditionalModifier: ViewModifier {
var isShowing: Bool
func body(content: Content) -> some View {
Group {
if self.isShowing {
content
.toolbar {
ToolbarItem(placement: .bottomBar, content: {
Button(action: {
}){
Image(systemName: "square.and.arrow.up")
}
})
}
.toolbar {
ToolbarItem(placement: .status, content: {
Text("Toolbar")
.fontWeight(.bold)
})
}
}
}
}}
I don't need else statement cause I only want to see Toolbar
else { content }
And here is my Tabbar inside ZStack. We're gonna overlay it with Text using Conditional modifier applied to Text
struct ContentView: View {
#State private var showToolbar: Bool = false
var body: some View {
Button(action: {
showToolbar.toggle()
}, label: {
Text(showToolbar ? "Show Tabbar" : "Show Toolbar")
}).padding()
ZStack {
TabView {
someView()
.tabItem {
Image(systemName: "placeholdertext.fill")
Text("Tab 1")
}
someView()
.tabItem {
Image(systemName: "placeholdertext.fill")
Text("Tab ")
}
someView()
.tabItem {
Image(systemName: "placeholdertext.fill")
Text("Tab 3")
}
}
Text("")
.modifier(conditionalModifier(isShowing: showToolbar))
}
}}
Final result
tabbar to toolbar
There's a new view modifier in iOS 16 that let you switch the tab bar and the bottom bar.
https://developer.apple.com/documentation/swiftui/view/toolbar(_:for:)
For example,
ContentView()
.toolbar(isSelecting ? .visible : .hidden, for: .bottomBar)
.toolbar(isSelecting ? .hidden : .visible, for: .tabBar)

Maintain navigation item button alignment in SwiftUI as second button is added & removed

I have a scenario where there will be one or two trailing buttons based upon some criteria. I would like to have it such that the buttons always align to trailing for visual consistency, but so far, they appear to center align, regardless of what I do.
Below is a minimum example showing this:
import SwiftUI
struct ContentView: View {
#State private var isButtonShown = true
var body: some View {
NavigationView {
Button(action: {
self.isButtonShown.toggle()
}, label: {
Text(self.isButtonShown ? "Hide Button" : "Show Button")
})
.navigationBarItems(trailing:
HStack {
if self.isButtonShown {
Button(action: {
print("A tapped")
}, label: {
Text("A")
})
Spacer(minLength: 30)
}
Button(action: {
print("B tapped")
}, label: {
Text("B")
})
}
.frame(alignment: .trailing)
)
}
}
}
And a video that shows what happens when I select the button.
My goal is to have B remain in the same position, regardless of whether or not A is shown.
Finally, I tried a few other items:
Moved .frame(alignment: .trailing) to the NavigationView level
Added an else after self.isButtonShown that added a Spacer()
Applied .frame(alignment: .trailing) to the B Button
It is know issue in SwiftUI 1.0
SwiftUI 2.0
The solution based on new .toolbar does not have it. Tested with Xcode 12 / iOS 14
struct ContentView: View {
#State private var isButtonShown = true
var body: some View {
NavigationView {
Button(action: {
self.isButtonShown.toggle()
}, label: {
Text(self.isButtonShown ? "Hide Button" : "Show Button")
})
.toolbar {
ToolbarItem(placement: .primaryAction) {
if self.isButtonShown {
Button(action: {
print("A tapped")
}, label: {
Text("A")
})
}
}
ToolbarItem(placement: .primaryAction) {
Button(action: {
print("B tapped")
}, label: {
Text("B")
})
}
}
}
}
}

Is there a way to open a contextmenu in SwiftUI with a „normal“ touch?

In the first Betas of Xcode 11 I have tried to create a dropdownmenu and found in beta 4 a very interesting new element: the contextmenu. I have implemented it to my view and it works fine. But I want to open it with a normal touch (like a button). Is there a way to open it immediatelly?
struct ContentView: View {
#State var Texte = "Push the Button"
var body: some View {
Text(self.Texte)
.contextMenu {
VStack {
Button(action: {
self.Texte = "Option 1"
}) {
Text("Select Option 1")
}
Button(action: {
self.Texte = "Option 2"
}) {
Text("Select Option 2")
}
}
}
}
}
This is possible now via Menu (iOS 14+)
Menus are covered in this WWDC video at ~11:15.
Playground Example:
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
var body: some View {
HStack {
// Other views
Text("Example View 1")
// Button, that when tapped shows 3 options
Menu {
Button(action: {
}) {
Label("Add", systemImage: "plus.circle")
}
Button(action: {
}) {
Label("Delete", systemImage: "minus.circle")
}
Button(action: {
}) {
Label("Edit", systemImage: "pencil.circle")
}
} label: {
Image(systemName: "ellipsis.circle")
}
}
.frame(width: 300, height: 300, alignment: .center)
}
}
PlaygroundPage.current.setLiveView(ContentView())
I don't think this will be ever possible. I assume you should use a popover.

Navigation stuff in SwiftUI

I'm trying to figure out how to use the navigation bar in SwiftUI
I want to put BarButtonItem and images inside the NavigationBar
I have been able to display the navigation bar and put titles
var body: some View {
NavigationView{
List(0...5) { note in
VStack(alignment: .leading) {
Text("title")
Text("Date")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.navigationBarTitle(Text("Notes"))
}
}
iOS 14
You should use the toolbar modifier:
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") { /* action */ }
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: { /* Actions */ }, label: {
HStack {
Image(systemName: "trash")
Text("Delete")
}
})
.foregroundColor(.red) // You can apply colors and other modifiers too
}
}
Note 1: You can have ANY View there. (not only a Button) and also any modifiers
Note 2: Both codes above and below will generate the same look items but with different approachs
iOS 13 and above (deprecated but still works)
You should use .navigationBarItems() modifier. For example you can add Button or Image like this:
.navigationBarItems(
leading: Button("Cancel") {
// Actions
},
trailing: Button(action: {
// Actions
}, label: { Label("Delete", systemImage: "trash") }
).foregroundColor(.red) // You can apply colors and other modifiers too
)
💡 Pro TIP
Always try to encapsulate each item in a separated struct, so your code will be simplified and very easy to replace with newer technologies. for example, take a look at this sample:
.navigationBarItems(
leading: MyCustomButtonItem(),
trailing: MyCustomButtonItem(text: "foo", image: "Bard")
)
.navigationBarItems() is the function you are looking for. You can specify a leading view, trailing view, or both. Within the view, you can specify horizontal and vertical stacks to add additional buttons.
var body: some View {
NavigationView{
List(0...5) { note in
VStack(alignment: .leading) {
Text("title")
Text("Date")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.navigationBarItems(leading: HStack {
Button(action: {}, label: {Image(systemName: "star.fill")})
Button(action: {}, label: {Text("Edit")})
}, trailing: VStack {
Button(action: {}, label: {Image(systemName: "star.fill")})
Button(action: {}, label: {Text("Edit")})
})
.navigationBarTitle(Text("Notes"))
}
}
SwiftUI 2
In SwiftUI 2 / iOS 14 the navigationBarItems modifier is deprecated.
Instead we should use a toolbar with ToolbarItems.
NavigationView {
List {
// ...
}
.navigationTitle("Notes")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Tap me") {
// action
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Image(systemName: "plus")
}
}
}
You can see the documentation for more ToolbarItemPlacements.
Check the image here
The toolbar() modifier lets us add single or multiple bar button items to the leading and trailing edge of a navigation view, as well as other parts of our view if needed. These might be tappable buttons, but there are no restrictions – you can add any sort of view.
var body: some View {
NavigationView {
ScrollView {
VStack{
}//: VStack
}//: Scroll
.navigationTitle("Settings")
.toolbar(content: {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button {
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "xmark")
}
}
})
.padding()
}//: Navigation
}
put this from parentViewController
NavigationLink(destination: NotesListView())

Resources