Переопределить функциональность кнопки из другого представления?

#swift #swiftui #swiftui-view

Вопрос:

У меня есть многоразовая панель поиска в отдельном представлении, которая выглядит следующим образом:

 
struct SearchBar: View {
    
    @Binding var searchText: String
    @Binding var isSearching: Bool
    
    var body: some View {
        HStack {
            HStack {
                TextField("Search terms here", text: $searchText)
            }
            .onTapGesture(perform: {
                isSearching = true
            })
            .overlay(
                HStack {
                    Image(systemName: "magnifyingglass")
                    
                    if isSearching {
                        Button(action: { searchText = "" }, label: {
                            Image(systemName: "xmark.circle.fill")     
                        })
                    }   
                }
            )
            if isSearching {
                Button(action: {
                    isSearching = false
                    searchText = ""
                    
                }, label: {
                    Text("Cancel")
                        
                })
            }
            
        }
    }
}
 

И я использую SearchBar в нескольких представлениях, как это:

 SearchBar(searchText: $textFieldSearch, isSearching: $isSearching)
 

Есть ли способ переопределить/добавить функциональность кнопки «Отмена»:

 Button(action: {
   isSearching = false
   searchText = ""
   // pass more functionality here dynamically
 }, 
  label: {
  Text("Cancel")   
})
 

В некоторых представлениях мне нужно сделать некоторые дополнительные вещи, помимо очистки searchText поля и установки isSearching значения false.

Ответ №1:

Вы можете использовать закрытие. Здесь я создал одно действие закрытия кнопки отмены и установил его как необязательное.

 struct SearchBar: View {
    
    @Binding var searchText: String
    @Binding var isSearching: Bool
    var cancel: (() -> Void)? // <== Here
    
    var body: some View {
        HStack {
            HStack {
                TextField("Search terms here", text: $searchText)
            }
            .onTapGesture(perform: {
                isSearching = true
            })
            .overlay(
                HStack {
                    Image(systemName: "magnifyingglass")
                    
                    if isSearching {
                        Button(action: { searchText = "" }, label: {
                            Image(systemName: "xmark.circle.fill")
                        })
                    }
                }
            )
            if isSearching {
                Button(action: {
                    isSearching = false
                    searchText = ""
                    cancel?() // <== Here
                }, label: {
                    Text("Cancel")
                    
                })
            }
            
        }
    }
}

 

Использование

 SearchBar(searchText: $textFieldSearch, isSearching: $isSearching)
SearchBar(searchText: $textFieldSearch, isSearching: $isSearching) {
    // Cancel Action
}
 

Комментарии:

1. ->> cancel?() , Как используется эта часть? Допустим, вы добавляете закрытие SearchBar , как показано, как должен выглядеть синтаксис внутри Button(action:...{}) ?

2. Сначала я объявляю закрытие отмены в представлении и вызываю его с помощью действия кнопки отмены. Закрытие-это единственное время выполнения функции, но без имени.

3. Хотя я не понимаю этой cancel?() части

4. Не могли бы вы, пожалуйста, уточнить у меня, хотите ли вы передавать данные из другого представления в представление поиска или из представления поиска в другое представление?

5. Хорошо, в одном представлении (и только в одном конкретном представлении), когда пользователь нажимает «Отмена», он должен вызвать вызываемую функцию clearResults() , которая просто вызывает API на мой сервер. Для всех других представлений, которые используют кнопку «отмена», мне нужна обычная функциональность: настройка isSearching = false и searchText = ""

Ответ №2:

Если вам нужно дополнительное действие, вы можете ввести onCancel побочный эффект, такой как

 struct SearchBar: View {
    
    @Binding var searchText: String
    @Binding var isSearching: Bool
    var onCancel: () -> Void = {}     // << default does nothing

    ...

            if isSearching {
                Button(action: {
                    isSearching = false
                    searchText = ""
                    onCancel()            // << here !!
                }, label: {
                    Text("Cancel")
                    
                })
            }
 

и используйте либо по умолчанию, как вы это делали, либо предоставляя побочный эффект, например

 SearchBar(searchText: $textFieldSearch, isSearching: $isSearching) {
  // side effect is here
}