UISearchBarを使用しています(ただし、通常は組み合わせて使用されるSearchDisplayControllerは使用していません)。[X]ボタンを押したときにキーボードを閉じたいと思います。
私は TomSwiftの提案 「X」がタップされたときに呼び出されることをフォローしました。これはうまく機能します。ただし、テキストフィールドからファーストレスポンダーを辞任し、UISearchBarインスタンスを呼び出しても、どちらもresignFirstResponder
を使用しても、キーボードが消えることはありません。
ユーザーがXボタンをタップしたときにキーボードを取り除く方法はありますか?
「クリア」通知を受け取るために私がしたことは次のとおりです。
- (void)viewDidLoad:
{
for (UIView* v in searchBar.subviews)
{
if ( [v isKindOfClass: [UITextField class]] )
{
UITextField *tf = (UITextField *)v;
tf.delegate = self;
break;
}
}
}
次に、UISearchBarDelegateとUITextFieldDelegateの両方を実装するようにクラスを設定します。
クラスをテキストフィールドデリゲートとして機能させることで、次の呼び出しを取得できます。
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
[textField resignFirstResponder];
[self.searchBar resignFirstResponder];
return YES;
}
私は考えられるすべてを試しました。私が試みている最後のことは、UISearchDelegateがControllerクラスで呼び出す 'searchBarCancelButtonClicked'を発行する方法を見つけることですが、UISearchBarには直接的なメソッドがないように見えるので、これをどのように実行できるかわかりませんこの名前で呼び出します。
更新:
まあ、これは完全なハックですが、私はそれを機能させることができました。基本的に、コードはキャンセルボタンのハンドラーを呼び出します。それを機能させるには、セレクターを遅らせて呼び出す必要がありましたが、なぜそうしなければならないのかわかりません。また、テキストフィールドの場合と同じように、キャンセルボタンのアクセサーを作成する必要がありました。
繰り返しますが、これは完全なハックです。アプリで自分でこれを行うかどうかはわかりません。
// this in the context of the search bar
- (UIButton*) cancelButton
{
for (UIView* v in self.subviews)
{
if ( [v isKindOfClass: [UIButton class]] )
return (UIButton*)v;
}
return nil;
}
// this is the textField delegate callback
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
[textField resignFirstResponder];
UIButton* cb = _searchBar.cancelButton;
NSObject* target = [[cb allTargets] anyObject];
NSArray* actions = [cb actionsForTarget: target forControlEvent:UIControlEventTouchUpInside];
NSString* selectorName = [actions objectAtIndex:0];
SEL selector = NSSelectorFromString( selectorName );
[target performSelector: selector withObject: cb afterDelay: 0.1];
return YES;
}
元の回答:
そもそも明確な「X」ボタンを表示するにはどうすればよいですか?私のテストケースでは、表示されていません...
TextFieldではなくsearchBarでresignFirstResponderを実行してみてください。
トムズの答えは私に考えさせました。ユーザーがクリアボタンをクリックしたときに検索バーがまだfirstResponderになっていない場合は、それが表示されるまで待ってから、resignFirstResponderにすることができます。つまり、次の線に沿って:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self performFilteringBySearchText: searchText]; // or whatever
// The user clicked the [X] button or otherwise cleared the text.
if([searchText length] == 0) {
[searchBar performSelector: @selector(resignFirstResponder)
withObject: nil
afterDelay: 0.1];
}
}
チャームのように機能し、トムのIMHOよりもハッキーではありません。
これは機能します:
[searchBar performSelector:@selector(resignFirstResponder) withObject:nil afterDelay:0.1];
Swift 3:に更新
ユーザーが検索フィールドに文字列を入力してxをクリックしたとすると、次のコードはxが押されたときにキーボードを非表示にするように機能します。
`
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
if searchBar.text == nil || searchBar.text == ""
{
searchBar.perform(#selector(self.resignFirstResponder), with: nil, afterDelay: 0.1)
}
}
`
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
SearchBar.showsCancelButton =NO;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[SearchBar resignFirstResponder];
}
performselector:WithObject:afterDelay:
を使用する代わりに、メインスレッドでUIを変更するべきではありませんか?
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length == 0) {
[searchBar performSelectorOnMainThread:@selector(resignFirstResponder) withObject:nil waitUntilDone:NO];
}
}
@radiospielの回答と、@ Tozar linked to:の回答を組み合わせて使用しました。
@interface SearchViewController : UIViewController <UISearchBarDelegate> {
// all of our ivar declarations go here...
BOOL shouldBeginEditing;
....
}
...
@end
@implementation SearchViewController
...
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
...
shouldBeginEditing = YES;
}
}
...
- (void) searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
// TODO - dynamically update the search results here, if we choose to do that.
if (![searchBar isFirstResponder]) {
// The user clicked the [X] button while the keyboard was hidden
shouldBeginEditing = NO;
}
else if ([searchText length] == 0) {
// The user clicked the [X] button or otherwise cleared the text.
[theSearchBar performSelector: @selector(resignFirstResponder)
withObject: nil
afterDelay: 0.1];
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)bar {
// reset the shouldBeginEditing BOOL ivar to YES, but first take its value and use it to return it from the method call
BOOL boolToReturn = shouldBeginEditing;
shouldBeginEditing = YES;
return boolToReturn;
}
@end
避けようとする
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
あなたのコードのメソッドはこれを解決できます
「x」ボタンをクリックすると、検索バーのテキストフィールドの文字列が空の文字のコレクションになります。
コレクションの長さを確認すると、「x」ボタンがクリックされたことを検出するのに役立ちます。
私は同様の問題があり、この解決策は私のために働きました:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
//let searchText = searchText.trimmingCharacters(in: .whitespaces)
if searchText.isEmpty{
DispatchQueue.main.async { [weak self] in
guard let self = self else{ return }
self.searchBar.resignFirstResponder()
}
}
}
EDIT:実際、以下はUISearchBarに接続されているデリゲートを壊します。 UISearchBarをサブクラス化し、UITextField Delegateメソッドを上書きするだけです。
===========================
UITextViewにアクセスするためにこれを行う必要がありました
for (UIButton* v in [self.searchBar.subviews[0] subviews])
{
if ( [v isKindOfClass: [UITextField class]] )
{
UITextField *tf = (UITextField *)v;
tf.delegate = self;
break;
}
}
クリアテキストフローの別の観点(@TomSwiftの回答に似ていますが、私にとってはより明確で、トリッキーではありません)また、検索バーを終了した後に[キャンセル]ボタンを非表示にし、ライブ検索を実装し(各シンボルの後に)、ユーザーが検索を完了する前にテーブルをカバーする必要があります。
//self.searchHoverView can cover table view
//performSearchWithSearchBar: method for performing search
#pragma mark - UISearchBarDelegate
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];
self.searchHoverView.hidden = NO;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length) {
[self performSearchWithSearchBar:searchBar];
} else {
UIButton *button;
for (UIView *subView in [searchBar subviews]) {
for (UIView *view in [subView subviews]) {
if ([view isKindOfClass:[UIButton class]]) {
button = (UIButton *)view;
break;
}
}
}
if (button) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
});
}
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
self.searchBar.text = nil;
[self.searchBar setShowsCancelButton:NO animated:YES];
[self.searchBar resignFirstResponder];
self.searchHoverView.hidden = YES;
}
元の回答に対するMaxhsのクレジット:これはSwift 2.2バージョン:私にとって魅力のように機能します
if searchBar.text == "" {
dispatch_async(dispatch_get_main_queue(), {
self.searchBar.resignFirstResponder()
})
}