WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Searchable Modifier

Forums > SwiftUI

Hello all,

I am having an issue with the .searchable modifier to a list. I'm going to describe as briefly as I can the issue.

To create a sacrament meeting program the user taps a button which brings up a sheet. Then to add hymns to the meeting on the current sheet the user taps another button and this navigates to a view to add the hymns. Now if you filter the list of hymns and choose one, when you tap the cancel button next to the searchbar it not only closes the keyboard, but it navigates back to the sheet and dismisses the sheet and the user has to start over again.

This only seems to happen on the iPad and not the iPhone or iPod.

Any help would be appreciated, I have been stuck on this for about a month now and I can't seem to find out why. The old internet doesn't seem to have an anwser or either I'm not searching for the right question (which could be possible). Here is the code on the sheet that has the searchable modifier.

struct NewAddHymnsToProgramView: View {
    @Environment(\.dismiss) var dismiss
    @EnvironmentObject var dataManager: DataManager

    //DMG-02-26: renamed draftDrogram to draftProgram
    @ObservedObject var draftProgram: DraftProgram

    // MDK01-18-22: Support for segmented control
    @State private var alphaNumericSegmentChoice = Constants.i0

    // MDK01-18-22: Support for segmented control
    @State private var catalogSegmentChoice = Constants.i0

    // MDK-01-30-22: Search Support
    @State private var isSearching = false
    @State private var searchTerm = ""

    var body: some View {
        VStack {
            // 1. Sort and Catalog Pickers
            SegmentedControlsView(alphaNumericSegmentChoice: $alphaNumericSegmentChoice, catalogSegmentChoice: $catalogSegmentChoice, showAlphaNumericFavs: .show)

            Text(.ahpvInstruction)
                .genericTextModifier(for: .subheadline, weight: .medium, color: .secondaryLabel)
                .extraSmallBottomPadding()
                .smallHorizontalPadding()

            // 2. List of hymns
            List {
                ForEach(dataManager.sectionedHymnData(segChoice: alphaNumericSegmentChoice, searchTerm: searchTerm), id: \.self) { section in
                    Section(header: SectionHeaderView(headerName: determineListOfHymns(section: section))) {
                        ForEach(section, id: \.id) { hymn in
                            NewAddHymnsToProgramRowView(program: draftProgram, hymn: hymn)
                        }
                    }
                }
            }
            .searchable(text: $searchTerm, placement: .navigationBarDrawer(displayMode: .always), prompt: .sbSearchByNameOrCategory)
        } // End of VStack
        .navigationTitle(draftProgram.name)
        .navigationBarTitleDisplayMode(.inline)
        .navigationBarBackButtonHidden(true)
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                Button(action: { dismiss() }, label: {
                    SFImage.chevronleft.image
                        .tint(.label)
                })
            }
        }
    }

    /**
     Will return the list of hymns based on the segment choice the user picks.

     DMGCloud2 -- type change to HymnProxy and use categoryName

     - Parameter section: An array of HymnProxy
     - Returns: A String representing the category name or first letter of the hymn
     */
    private func determineListOfHymns(section: [Hymn]) -> String {
        if alphaNumericSegmentChoice == Constants.i0 {
            return section[Constants.i0].categoryName
        } else {
            return section[Constants.i0].firstLetter
        }
    }
}

   

Instead of code, perhaps you can provide a Keynote drawing of your architecture, or your intentions?

As I recall from the scripture of St Paul of Swift, action sheets are designed for small blessings. [cit. needed]

It seems you're trying to have a sheet that calls another sheet which includes a search bar? Perhaps your architecture isn't suited to performing a miracle of this magnitude?

Perhaps in your design you have a Ritual object. That object might have one or more Prayers, Spells, Incantations, or Songs. Your Prayer or Spell object might have one or more Implements such as Incense, Wooden Stakes, Relics and the like.

@twoStraws, our Level 100+ Mage, has several videos using NavigationViews to transmogrify views between one-to-many relationships. I tend to think this is the architecture you should be using to add hymns, hexes, songs, incantations, and liturgical accoutrements to your main sacrement object. It's natural world order to navigate between views.

I am not sure navigating between sheets is a good thing. It feels other-worldly. This is why it might be helpful to see your Biblia Vulgata, your grand architecture.

   

Hello all,

I am not sure if what is was asking was very clear above. The problem I was having was that the .searchable modifier which gives us a UISearchController and UISearchBar equivalent in SwiftUI was giving me some issues. The issue I was having was that one of the sheets I present to the user has the .searchable modifier on the list.

So if you were filtering the list (which worked perfectly) once you tapped the cancel button to the right of the searchbar it would not only dismiss the searchbar but it would also dismiss the sheet as well.

So I came up with a solution that works for me after some research and trail and error. Heres what I found out about the new .searchable. It has two Environment values called isSearching and dismissSearch. Both of these environment values need to be declared and used inside a child view, they will not work on the main view that has the searchbar from what I can tell and have read in documentation.

So for me I have a rowView that displays all the list items on the main sheet. So to stop the sheet from dismissing when tapping the cancel button next the the search bar. I did the following:

  1. Declared the dismiss search
  2. In the onTapGesture I called hideKeyboard() and dismissSearch()

These steps stopped the sheet from dismissing and cleared the search bar.

@Environment(\.dismissSearch) var dismissSearch

.onTapGesture {
    // Was having trouble with the sheet getting dismissed everytime I tapped
    // the cancel button to the right of the search bar. To make sure that doesn't
    // happen anymore I use the dismissSearch environment value provided by the
    // .searchable modifier along with a hideKeyboard function that I created. I
    // think Paul Hudson demonstrated how to hide keyboard. Thats it.
    dismissSearch()
    hideKeyboard()

    if !checked {
        withAnimation(Animation.easeIn(duration: Constants.pt8)) {
            trimVal = Constants.f1
            checked.toggle()
        }
    } else {
        withAnimation {
            trimVal = Constants.f0
            checked.toggle()
        }
    }
    changeHymnStatus()
}

Heres my hide keyboard function

#if canImport(UIKit)
extension View {
    func hideKeyboard() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}
#endif

I hope this helps others who may be facing this issue as well. When I did a search on the internet there was nothing I could find that talked about this.

   

I'm having an almost identicle issue. Can you elaborate on your fix? Where did you implemented the onTapGesture modifier? This bug is difficult. The same searchable list will both present this bug and function normally depending on which place in the app the view is called - I can't see any significant differences that are causing it!

   

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.