代码之家  ›  专栏  ›  技术社区  ›  Jens Kohl

uiSearchBar ClearButton强制显示键盘

  •  43
  • Jens Kohl  · 技术社区  · 15 年前

    我有一个uisearchbar,它充当表视图的实时过滤器。当通过endeding:关闭键盘时,查询文本和灰色圆形“清除”按钮将保留。从这里,如果我点击灰色的“清除”按钮,键盘会在清除文本时重新出现。

    我该如何预防?如果键盘当前未打开,我希望该按钮在不重新打开键盘的情况下清除文本。

    当我点击清除按钮时,有一个协议方法被调用。但是向uisearchbar发送resignfirstresponder消息对键盘没有任何影响。

    12 回复  |  直到 15 年前
        1
  •  120
  •   boliva    14 年前

    这是一个古老的问题,我刚刚遇到了同样的问题,并通过以下方式解决了它:

    searchBar:textDidChange: 调用uisearchbardelegate的方法是因为用户点击“清除”按钮,搜索栏还没有成为第一响应者,因此我们可以利用它来检测用户实际上打算何时清除搜索,而不是将焦点转移到搜索栏和/或执行其他操作。

    为了跟踪这一点,我们需要声明 BOOL 我们的viewController中的ivar也是searchbar委托(我们称之为 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中,我们实现 搜索栏: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;
    }
    

    基本上就是这样。

    最好的

        2
  •  33
  •   Gregory Cosmo Haun    14 年前

    我发现当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];   
    }
    
        3
  •  9
  •   General Failure shilu    7 年前

    我找到了一个非常安全的方法来知道是否已按下清除按钮,并忽略用户刚刚删除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时单击“清除”按钮,则会有两个ping,而如果用户在不编辑时单击,则只有一个ping。


    编辑: 我不能测试它,但这里是根据rotem的swift版本:

    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!")
        }
    }
    
        4
  •  8
  •   Community CDub    7 年前

    我使用了@boliva的答案和@radiospiel的组合 answer 另一个问题是:

    @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
    
        5
  •  3
  •   Peter Lapisu    11 年前

    根据我的经验,最好的解决办法就是 UIButton (背景清晰,无文本)在系统清除按钮上方,然后连接 IBAction

    使用自动布局非常简单

    - (IBAction)searchCancelButtonPressed:(id)sender {
    
        [self.searchBar resignFirstResponder];
        self.searchBar.text = @"";
    
        // some of my stuff
        self.model.fastSearchText = nil;
        [self.model fetchData];
        [self reloadTableViewAnimated:NO];
    
    }
    
        6
  •  1
  •   luismgb    6 年前

    按ui搜索栏中的“清除”按钮会自动打开键盘,即使您调用 searchBar.resignFirstResponder() textDidChange uiSearchBardelegate方法。

    要在按“x”清除uisearchbar时实际隐藏键盘,请使用以下代码。这样,即使 文本转换 在uisearchbar中键入内容时调用,仅当删除其中的所有文本、使用“删除”按钮或单击“x”时才隐藏键盘:

    extension ViewController: UISearchBarDelegate {
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            if searchBar.text!.count == 0 {
                DispatchQueue.main.async {
                    searchBar.resignFirstResponder()
                }
            } else {
                // Code to make a request here.
            }
        }
    }
    
        7
  •  0
  •   Corey Floyd    15 年前

    在您的结束方法中,为什么不清除uisearchbar?因为你也必须在那里辞职,所以这是有道理的。

        8
  •  0
  •   Kendall Helmstetter Gelner    15 年前

    在搜索栏中,委托呼叫要求您接受从旧值更改为新值的更改-您可以检测到新值为零,旧值不为零,以及自键盘上次打开以来用户未键入任何内容的指示器-然后在这种情况下,放弃搜索栏的第一响应者。但不确定键盘是否会立即显示。

    我有一个非常相似的情况,我自己也可以试试。

        9
  •  0
  •   H K    10 年前

    触摸清除按钮会导致 searchText 是空的。实现这一点的另一种方法是检查 - (void)searchBar:(UISearchBar *)bar textDidChange:(NSString *)searchText :

    - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
    {
        if([searchText length] == 0)
        {
            [self dismissSearch];
        }
        else
        {
            self.searchResultsTable.hidden = YES;
            [self handleSearchForString:searchText];
        }
    }
    
    - (void)dismissSearch
    {
        [self.searchBar performSelector: @selector(resignFirstResponder)
                      withObject: nil
                      afterDelay: 0.1];
    
        self.searchResultsTable.hidden = YES;
    }
    
        10
  •  0
  •   mikeho    9 年前

    对于那些使用 UISearchController 在里面 IOS 8 向上,您只需将 ui搜索控制器 . 为了完整性,您还可能希望隐藏 取消 按钮,正如我所做的,自从清除 UISearchBar 实际上是在搜索中取消。如果你想用的话,我已经在下面添加了代码。

    这样做的好处是,您可以将它用于任何类和视图,而不需要 UIViewController . 我甚至将包括如何初始化 ui搜索控制器 在这个解决方案的底部。

    FJ探查杆

    只有当您像我一样希望隐藏“取消”按钮时,才需要重写这个类。标记 searchController.searchBar.showsCancelButton = NO 好像不适合 IOS 8 . 我还没测试过 IOS 9 .

    fjSouthBar

    空的,但为了完整起见放在这里。

    @import UIKit;
    
    @interface FJSearchBar : UISearchBar
    
    @end
    

    F.S.

    #import "FJSearchBar.h"
    
    @implementation FJSearchBar
    
    - (void)setShowsCancelButton:(BOOL)showsCancelButton {
        // do nothing
    }
    
    - (void)setShowsCancelButton:(BOOL)showsCancelButton animated:(BOOL)animated {
        // do nothing
    }
    
    @end
    

    FJ搜索控制器

    这里是你想要真正改变的地方。我分裂了 UISearchBarDelegate 因为,imho,这些类别使类更干净,更容易维护。如果您希望将委托保持在主类接口/实现中,那么非常欢迎您这样做。

    FJ搜索控制器.h

    @import UIKit;
    
    @interface FJSearchController : UISearchController
    
    @end
    
    @interface FJSearchController (UISearchBarDelegate) <UISearchBarDelegate>
    
    @end
    

    FJ搜索控制器.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: 如果只希望在用户按 搜索 按钮。
        11
  •  0
  •   swordray    7 年前

    @boliva答案的快速版本。

    class MySearchContentController: UISearchBarDelegate {
    
        private var searchBarShouldBeginEditing = true
    
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            searchBarShouldBeginEditing = searchBar.isFirstResponder
        }
    
        func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
            defer {
                searchBarShouldBeginEditing = true
            }
            return searchBarShouldBeginEditing
        }
    }
    
        12
  •  -1
  •   Perlguy Vito Royeca    9 年前

    我已经碰到过好几次了。我真的很感激人们给出的答案。

    最后,我真的很想看到苹果只允许我们(开发者)检测什么时候按下了清除按钮。

    很明显,按下它会被检测到,因为搜索框中的任何文本都会被清除。

    我猜他们现在的优先顺序不是很高…但我真的希望苹果公司的人能给uisearchbar一点爱!