37

我已经在表格视图中实现了一个 UISearchBar 并且几乎所有东西都在工作,除了一件小事:当我输入文本然后按下键盘上的搜索按钮时,键盘消失了,搜索结果是表中显示的唯一项目,文本保留在 UISearchBar 中,但取消按钮被禁用。

我一直试图让我的列表尽可能接近 Apple 联系人应用程序的功能,当您在该应用程序中按下搜索时,它不会禁用取消按钮。

当我查看 UISearchBar 头文件时,我注意到 _searchBarFlags 结构下的 autoDisableCancelButton 标志,但它是私有的。

设置 UISearchBar 时有什么遗漏吗?

4

11 回答 11

51

我找到了解决方案。您可以使用这个 for 循环来循环搜索栏的子视图,并在按下键盘上的搜索按钮时启用它。

for (UIView *possibleButton in searchBar.subviews)
{
    if ([possibleButton isKindOfClass:[UIButton class]])
    {
        UIButton *cancelButton = (UIButton*)possibleButton;
        cancelButton.enabled = YES;
        break;
    }
}
于 2010-12-03T19:10:57.670 回答
15

我必须稍微调整一下才能让它在 iOS7 中为我工作

- (void)enableCancelButton:(UISearchBar *)searchBar
{
    for (UIView *view in searchBar.subviews)
    {
        for (id subview in view.subviews)
        {
            if ( [subview isKindOfClass:[UIButton class]] )
            {
                [subview setEnabled:YES];
                NSLog(@"enableCancelButton");
                return;
            }
        }
    }
}
于 2013-08-09T16:03:56.303 回答
5

有两种方法可以轻松实现

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
    //  The small and dirty
    [(UIButton*)[searchBar valueForKey:@"_cancelButton"] setEnabled:YES];

    // The long and safe
     UIButton *cancelButton = [searchBar valueForKey:@"_cancelButton"];
    if ([cancelButton respondsToSelector:@selector(setEnabled:)]) {
         cancelButton.enabled = YES;
    }
}

您应该使用第二个,如果 Apple 在后台更改它,它不会使您的应用程序崩溃。

顺便说一句,我从 iOS 4.0 到 8.2 对其进行了测试,没有任何变化,我也在我的商店批准的应用程序中使用它,没有任何问题。

于 2015-01-12T22:25:09.247 回答
3

这就是让它在 iOS 6 上为我工作的原因:

searchBar.showsCancelButton = YES;
searchBar.showsScopeBar = YES;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:YES animated:YES];
于 2012-11-01T02:11:19.827 回答
3

这是我的解决方案,适用于所有 iOS 版本的所有情况。

IE,当键盘因为用户拖动滚动视图而被解除时,其他解决方案无法处理。

- (void)enableCancelButton:(UIView *)view {
    if ([view isKindOfClass:[UIButton class]]) {
        [(UIButton *)view setEnabled:YES];
    } else {
        for (UIView *subview in view.subviews) {
            [self enableCancelButton:subview];
        }
    }
}

// This will handle whenever the text field is resigned non-programatically
// (IE, because it's set to resign when the scroll view is dragged in your storyboard.)
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
    [self performSelector:@selector(enableCancelButton:) withObject:searchBar afterDelay:0.001];
}

// Also follow up every [searchBar resignFirstResponder];
// with [self enableCancelButton:searchBar];
于 2014-01-13T05:39:48.057 回答
3

根据我在这里的回答,将其放在您的 searchBar 委托中:

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{   
    dispatch_async(dispatch_get_main_queue(), ^{
        __block __weak void (^weakEnsureCancelButtonRemainsEnabled)(UIView *);
        void (^ensureCancelButtonRemainsEnabled)(UIView *);
        weakEnsureCancelButtonRemainsEnabled = ensureCancelButtonRemainsEnabled = ^(UIView *view) {
            for (UIView *subview in view.subviews) {
                if ([subview isKindOfClass:[UIControl class]]) {
                    [(UIControl *)subview setEnabled:YES];
                }
                weakEnsureCancelButtonRemainsEnabled(subview);
            }
        };

        ensureCancelButtonRemainsEnabled(searchBar);
    });
}
于 2014-09-05T12:53:08.213 回答
2

没有一个答案对我有用。我的目标是 iOS 7。但我找到了答案。

我正在尝试的是类似于 Twitter iOS 应用程序的东西。如果您单击“时间线”选项卡中的放大镜,UISearchBar则会出现“取消”按钮激活、键盘显示和最近搜索屏幕。滚动最近的搜索屏幕,它会隐藏键盘,但会保持“取消”按钮处于激活状态。

这是我的工作代码:

UIView *searchBarSubview = self.searchBar.subviews[0];
NSArray *subviewCache = [searchBarSubview valueForKeyPath:@"subviewCache"];
if ([subviewCache[2] respondsToSelector:@selector(setEnabled:)]) {
    [subviewCache[2] setValue:@YES forKeyPath:@"enabled"];
}

我通过在表格视图的scrollViewWillBeginDragging:. 我查看了我的UISearchBar并显示了它的子视图。它总是只有一个类型UIView(我的变量searchBarSubview)。

在此处输入图像描述

然后,它UIView包含一个NSArray被调用subviewCache的元素,我注意到最后一个元素,即第三个元素,是 type UINavigationButton,而不是在公共 API 中。所以我开始改用键值编码。我检查了是否UINavigationButton响应setEnabled:,幸运的是,它响应。所以我将属性设置为@YES. 原来那UINavigationButton 取消按钮。

如果苹果决定改变 a 的实现,这势必会被打破UISearchBar,但到底是什么。它现在有效。

于 2014-02-25T17:20:49.780 回答
2

这是一个 Swift 3 解决方案,它利用扩展轻松获取取消按钮:

extension UISearchBar {
    var cancelButton: UIButton? {
        for subView1 in subviews {
            for subView2 in subView1.subviews {
                if let cancelButton = subView2 as? UIButton {
                    return cancelButton
                }
            }
        }
        return nil
    }
}

现在的用法:

class MyTableViewController : UITableViewController, UISearchBarDelegate {

    var searchBar = UISearchBar()

    func viewDidLoad() {
        super.viewDidLoad()
        searchBar.delegate = self
        tableView.tableHeaderView = searchBar
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        DispatchQueue.main.async {
            if let cancelButton = searchBar.cancelButton {
                cancelButton.isEnabled = true
                cancelButton.isUserInteractionEnabled = true
            }
        }
    }
}
于 2017-04-07T23:20:31.207 回答
1

对于 Monotouch 或 Xamarin iOS,我有以下适用于 iOS 7 和 iOS 8 的 C# 解决方案:

foreach(UIView view in searchBar.Subviews)
{
    foreach(var subview in view.Subviews)
    {
        //Console.WriteLine(subview.GetType());
        if(subview.GetType() == typeof(UIButton))
        {
            if(subview.RespondsToSelector(new Selector("setEnabled:")))
            {
                UIButton cancelButton = (UIButton)subview;
                cancelButton.Enabled = true;
                Console.WriteLine("enabledCancelButton");
                return;
            }
        }
    }
}

这个答案基于大卫道格拉斯的解决方案。

于 2015-01-09T14:31:26.547 回答
1

更完整的答案:

  • 从 iOS 7 开始,在 searchBar 下多了一层子视图
  • 启用取消按钮的好地方是searchBarTextDidEndEditing

.

extension MyController: UISearchBarDelegate {
  public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    DispatchQueue.main.async {
    // you need that since the disabling will
    // happen after searchBarTextDidEndEditing is called
      searchBar.subviews.forEach({ view in
        view.subviews.forEach({ subview in
          // ios 7+
          if let cancelButton = subview as? UIButton {
            cancelButton.isEnabled = true
            cancelButton.isUserInteractionEnabled = true
            return
          }
        })
        // ios 7-
        if let cancelButton = subview as? UIButton {
          cancelButton.isEnabled = true
          cancelButton.isUserInteractionEnabled = true
          return
        }
      })
    }
  }
}
于 2016-12-04T04:05:59.620 回答
0

时光荏苒,问题依旧……

优雅的Swift 5/iOS 13解决方案:

func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    for case let cancelButton as UIButton in searchBar.subviews {
        cancelButton.isEnabled = true
    }
}
于 2020-06-17T05:25:56.433 回答