SwiftUI .toolbar not showing at bottom of screen
James Creston
Posted on June 7, 2024
Hello, new coder here learning SwiftUI for the first time. Started an iOS coding journey this year after having not coded since 2005 when I last coded a social media website using html, css, and cold fusion7.
I have been following tutorials for a while and just cannot get past this bug that doesn’t generate any errors.
I may have my .toolbar embedded is the wrong area of my View Controller.
But my tool bar refuses to show at the bottom of the screen.
See the two screen shots. One shows the toolbar but the report title and select button are not at the stop of the screen.
The other is where I fixed the select/edit button but now the toolbar is missing.
import SwiftUI
import PhotosUI
struct ReportDetailView: View {
@Binding var report: Report
@State private var showPhotoLibrary = false
@State private var showCamera = false
@State private var selectedImages: [UIImage] = []
@State private var selectedImage: UIImage?
@State private var selectedImageIndex: Int?
@State private var showEditCaption = false
@State private var showEmailSheet = false
@State private var isSelecting = false
@State private var selectedPhotos = Set<Int>()
var body: some View {
VStack {
TextField("Report Title", text: Binding(
get: { report.title ?? "" },
set: { report.title = $0 }
))
.font(.largeTitle)
.padding(.top)
.background(Color.clear)
.frame(maxWidth: .infinity, alignment: .leading)
.textInputAutocapitalization(.words)
.onTapGesture {
self.dismissKeyboard()
}
.padding(.horizontal)
if report.photos.isEmpty {
Text("No Photos")
.foregroundColor(.gray)
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
} else {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))]) {
ForEach(report.photos.indices, id: \.self) { index in
VStack {
if let photo = report.photos[index].image {
Image(uiImage: photo)
.resizable()
.aspectRatio(contentMode: .fit)
.onTapGesture {
if isSelecting {
if selectedPhotos.contains(index) {
selectedPhotos.remove(index)
} else {
selectedPhotos.insert(index)
}
} else {
selectedImage = report.photos[index].image
selectedImageIndex = index
showEditCaption = true
}
}
.overlay(
isSelecting ?
Circle()
.stroke(selectedPhotos.contains(index) ? Color.blue : Color.clear, lineWidth: 3)
.frame(width: 30, height: 30)
.padding(5)
.background(Color.white.opacity(0.7).clipShape(Circle()))
.padding()
: nil
)
}
Text(report.photos[index].caption)
.font(.caption)
}
}
}
}
}
}
.navigationBarItems(trailing: Button(action: {
isSelecting.toggle()
selectedPhotos.removeAll()
}) {
Text(isSelecting ? "Cancel" : "Edit")
})
.toolbar {
ToolbarItem(placement: .bottomBar) {
HStack {
if isSelecting {
Button(action: deleteSelectedPhotos) {
Image(systemName: "trash")
.foregroundColor(.red)
}
Spacer()
}
Button(action: { showPhotoLibrary = true }) {
Image(systemName: "photo.on.rectangle.angled")
}
Spacer()
Button(action: { showCamera = true }) {
Image(systemName: "camera")
}
Spacer()
Button(action: { showEmailSheet = true }) {
Image(systemName: "envelope")
}
}
}
}
.sheet(isPresented: $showPhotoLibrary) {
UnifiedPicker(pickerType: .photoLibrary(single: false), selectedImages: $selectedImages)
.onDisappear {
for image in selectedImages {
if let imageData = image.jpegData(compressionQuality: 1.0) {
report.photos.append(Photo(imageData: imageData, caption: ""))
}
}
selectedImages.removeAll()
}
}
.sheet(isPresented: $showCamera) {
UnifiedPicker(pickerType: .camera, selectedImages: $selectedImages)
.onDisappear {
if let image = selectedImages.first, let imageData = image.jpegData(compressionQuality: 1.0) {
report.photos.append(Photo(imageData: imageData, caption: ""))
}
selectedImages.removeAll()
}
}
.sheet(isPresented: $showEditCaption) {
if let selectedIndex = selectedImageIndex {
EditCaptionView(photo: $report.photos[selectedIndex])
}
}
.sheet(isPresented: $showEmailSheet) {
if let emailData = emailData {
MailComposeViewController(mailData: emailData)
}
}
}
private func deleteSelectedPhotos() {
for index in selectedPhotos.sorted(by: >) {
report.photos.remove(at: index)
}
selectedPhotos.removeAll()
isSelecting.toggle()
}
private func dismissKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
private var emailData: Data? {
return PDFGenerator.generatePDF(for: report)
}
}
struct ReportDetailView_Previews: PreviewProvider {
@State static var report = Report(title: "Sample Report", date: Date(), photos: [])
static var previews: some View {
ReportDetailView(report: $report)
}
}
Posted on June 7, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.