45

テーブルビューのライブフィルターとして機能するUISearchBarがあります。endEditing:を使用してキーボードを閉じると、クエリテキストと灰色の円形の「クリア」ボタンが残ります。ここから、灰色の「クリア」ボタンをタップすると、テキストがクリアされるとキーボードが再表示されます。

これを防ぐにはどうすればよいですか?キーボードが現在開いていない場合は、キーボードを再度開かずにそのボタンでテキストをクリアしたいと思います。

クリアボタンをタップすると呼び出されるプロトコルメソッドがあります。ただし、UISearchBarにresignFirstResponderメッセージを送信しても、キーボードには何の影響もありません。

4

12 に答える 12

124

これは古い質問で、同じ問題に遭遇し、次の方法で解決できました。

ユーザーが「クリア」ボタンをタップしたために UISearchBarDelegateのメソッドが呼び出されたときsearchBar:textDidChange:、searchBar はまだファーストレスポンダになっていないため、ユーザーが実際にいつクリアしようとしたかを検出するためにそれを利用できます。検索して検索バーにフォーカスを移動しない、および/または何か他のことを行う。

それを追跡するにBOOLは、searchBarデリゲートでもあるviewControllerでivarを宣言し(それを と呼びましょうshouldBeginEditing)、初期値を設定する必要がありますYES(viewControllerクラスがSearchViewControllerと呼ばれると仮定します):

@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;
    }
}
...
@end

後で、UISearchBarDelegate でメソッドsearchBar:textDidChange:searchBarShouldBeginEditing:メソッドを実装します。

- (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText {
    NSLog(@"searchBar:textDidChange: isFirstResponder: %i", [self.searchBar isFirstResponder]);
    if(![searchBar isFirstResponder]) {
        // user tapped the 'clear' button
        shouldBeginEditing = NO;
        // do whatever I want to happen when the user clears the search...
    }
}


- (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;
}

基本的にはそれだけです。

一番

于 2010-10-04T02:36:41.147 に答える
33

「クリアボタン」へのタッチから textDidChange が呼び出されたときに、resignFirstResponder が機能しないことがわかりました。ただし、使用performSelection: withObject: afterDelay:は効果的な回避策のようです。

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if ([searchText length] == 0) {
        [self performSelector:@selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
    }
}

- (void)hideKeyboardWithSearchBar:(UISearchBar *)searchBar
{   
    [searchBar resignFirstResponder];   
}
于 2010-05-12T22:22:00.483 に答える
10

クリアボタンが押されたかどうかを知るための非常に安全な方法を見つけ、ユーザーが UISearchBar の最後の文字を削除しただけの時間を無視しました。ここにあります :

- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    _isRemovingTextWithBackspace = ([searchBar.text stringByReplacingCharactersInRange:range withString:text].length == 0);

    return YES;
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if (searchText.length == 0 && !_isRemovingTextWithBackspace)
    {
        NSLog(@"Has clicked on clear !");
    }
}

かなり単純明快ですよね :) ? 注意すべき唯一のことは、ユーザーが UISearchBar の UITextField を編集するときにクリア ボタンをクリックすると、2 つの ping が発生するのに対して、ユーザーが編集されていないときにクリックした場合は 1 つしか得られないことです。


編集:テストすることはできませんが、Rotemによると、これが迅速なバージョンです:

var isRemovingTextWithBackspace = false

func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool
{
    self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0)
    return true
}

func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
    if searchText.characters.count == 0 && !isRemovingTextWithBackspace
    { 
        NSLog("Has clicked on clear !")
    }
}

@Rotem の更新 (Swift2):

var isRemovingTextWithBackspace = false

func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    self.isRemovingTextWithBackspace = (NSString(string: searchBar.text!).stringByReplacingCharactersInRange(range, withString: text).characters.count == 0)
    return true
}

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.characters.count == 0 && !isRemovingTextWithBackspace {
        NSLog("Has clicked on clear!")
    }
}
于 2015-06-18T09:46:04.567 に答える
8

@bolivaの回答と、別のSOの質問に対する@radiospielの回答を組み合わせて使用​​しました。

@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
于 2012-12-08T06:44:25.083 に答える
0

検索バーのデリゲート呼び出しのうち、古い値から新しい値への変更を受け入れるように求められます-新しい値がnilであり、古い値がnilではないこと、およびユーザーがnilではなかったことを示すインジケーターを検出できますキーボードが最後に上がってから何かを入力しました。その場合、検索バーのファーストレスポンダーを辞任します。ただし、キーボードが一時的に表示されるかどうかはわかりません。

私は非常によく似た状況にあり、自分でそれを試すかもしれません。

于 2009-07-07T15:47:06.443 に答える
0

endEditing メソッドで、UISearchBar をクリアしてみませんか? それはファーストレスポンダーも辞任する場所でなければならないので、それは理にかなっています.

于 2009-07-07T13:36:51.863 に答える
0

iOS 8 以降で を使用しているUISearchController場合は、単純に をサブクラス化する必要があります。完全を期すために、私が行ったようにキャンセルボタンを非表示にすることもできます。使用したい場合は、そのコードを以下に追加しました。UISearchControllerUISearchBar

これの利点は、 のサブクラスを要求するのではなく、任意のクラスおよび任意のビューにこれを使用できることですUIViewControllerUISearchControllerこのソリューションの最後に、初期化方法も含めます。

FJSearchBar

このクラスは、私が行ったようにキャンセル ボタンを非表示にする場合にのみオーバーライドする必要があります。マーキングはiOS 8searchController.searchBar.showsCancelButton = NOでは機能しないようです。iOS 9はテストしていません。

FJSearchBar.h

空ですが、完全を期すためにここに配置されています。

@import UIKit;

@interface FJSearchBar : UISearchBar

@end

FJSearchBar.m

#import "FJSearchBar.h"

@implementation FJSearchBar

- (void)setShowsCancelButton:(BOOL)showsCancelButton {
    // do nothing
}

- (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
    // do nothing
}

@end

FJSearchController

ここで、実際の変更を行います。UISearchBarDelegateカテゴリを独自のカテゴリに分割したのは、私見ですが、カテゴリによってクラスがクリーンになり、保守が容易になるためです。デリゲートをメイン クラス インターフェイス/実装内に保持したい場合は、そうすることを歓迎します。

FJSearchController.h

@import UIKit;

@interface FJSearchController : UISearchController

@end

@interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>

@end

FJSearchController.m

#import "FJSearchController.h"
#import "FJSearchBar.h"

@implementation FJSearchController {
@private
    FJSearchBar *_searchBar;
    BOOL _clearedOutside;
}

- (UISearchBar *)searchBar {
    if (_searchBar == nil) {
        // if you're not hiding the cancel button, simply uncomment the line below and delete the FJSearchBar alloc/init
        // _searchBar = [[UISearchBar alloc] init];
        _searchBar = [[FJSearchBar alloc] init];
        _searchBar.delegate = self;
    }
    return _searchBar;
}

@end

@implementation FJSearchController (UISearchBarDelegate)

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
    // if we cleared from outside then we should not allow any new editing
    BOOL shouldAllowEditing = !_clearedOutside;
    _clearedOutside = NO;
    return shouldAllowEditing;
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    // hide the keyboard since the user will no longer add any more input
    [searchBar resignFirstResponder];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    if (![searchBar isFirstResponder]) {
        // the user cleared the search while not in typing mode, so we should deactivate searching
        self.active = NO;
        _clearedOutside = YES;
        return;
    }
    // update the search results
    [self.searchResultsUpdater updateSearchResultsForSearchController:self];
}

@end

注意すべきいくつかの部分:

  1. BOOLプロパティの代わりにプライベート変数として 検索バーとを配置しました。
    • それらは私有地よりも軽量です。
    • 外部から見たり変更したりする必要はありません。
  2. searchBarがファーストレスポンダーかどうかを確認します。そうでない場合は、テキストが空であり、もはや検索していないため、実際に検索コントローラーを無効にします。本当に確認したい場合は、 searchText.length == 0.
  3. searchBar:textDidChange:の前に呼び出されるsearchBarShouldBeginEditing:ため、この順序で処理しました。
  4. テキストが変更されるたびに検索結果を更新しますが、ユーザーが [検索[self.searchResultsUpdater updateSearchResultsForSearchController:self];] ボタンを押した後にのみ検索を実行する場合は、 を に移動することをお勧めします。searchBarSearchButtonClicked:
于 2016-03-06T00:59:29.957 に答える
-1

私はこれに数回遭遇しました。人々が与えてくれた答えに本当に感謝しています。

最終的には、Apple が私たち (開発者) にクリア ボタンが押されたことを検出できるようにしてほしいと思います。

検索ボックス内のテキストがクリアされるため、押したことが検出されることは明らかです。

現時点では優先順位のリストでそれほど高くないと推測しています...しかし、Appleの誰かがUISearchBarに少し愛を与えてくれることを本当に望んでいます!

于 2016-04-12T14:05:57.320 に答える