自定义 iOS 中 UISearchbar 的 UITextfield

13
我正在尝试自定义UISearchBar的文本字段。下图显示了我完成一半的工作。 strong text 我已经对UISearchBar进行了子类化,并从我的视图控制器中调用它。我想要从文本字段中移除那些深灰色的线条。以下是将UISearchBar添加到视图控制器的实现。
searchbar = [[SearchBar alloc] initWithFrame:CGRectMake(35,78, 250, 17)];
searchbar.backgroundColor = [UIColor clearColor];
searchbar.layer.borderColor = [[UIColor clearColor] CGColor];
searchbar.layer.borderWidth = 0;

for(UIView *view in searchbar.subviews){
    if([view isKindOfClass:[UITextField class]]){
        UITextField *tf= (UITextField *)view;
        tf.layer.borderColor = [[UIColor clearColor] CGColor];
        tf.delegate = self;
        break;
    }
}
[self.view addSubview:searchbar];
searchbar.delegate = self;

UISearchBar子类:

   - (id)initWithFrame:(CGRect)frame
  {
   self = [super initWithFrame:frame];
if (self) {
      // Initialization code
     }
     return self;
}

-(void)layoutSubviews{
     UITextField *searchField;
     [[[self subviews] objectAtIndex:0] removeFromSuperview];
     [self setTintColor:[UIColor clearColor]];
     self.clipsToBounds = YES;
     NSUInteger numViews = [self.subviews count];
     for(int i = 0; i < numViews; i++) {
        if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]]) { 
            searchField = [self.subviews objectAtIndex:i];
             searchField.leftViewMode = UITextFieldViewModeNever;
             searchField.backgroundColor = [UIColor clearColor];

        }


    }
    if(!(searchField == nil)) {            
        searchField.backgroundColor = [UIColor clearColor];
        searchField.textColor = [UIColor blackColor];
        searchField.frame = CGRectMake(self.frame.origin.x,self.frame.origin.y,self.frame.size.width,self.frame.size.height-10);

        [searchField setBorderStyle:UITextBorderStyleRoundedRect];

    }

    [super layoutSubviews];

}

我正在尝试实现类似于这样的效果: 文本字段不应具有任何边界。 图标是扁平化的UIImageView。

输入图像描述

9个回答

51

这是从UISearchBar子视图层次结构中获取文本字段并根据需要设置其属性的简单方法,例如:

  UITextField *txfSearchField = [searchbar valueForKey:@"_searchField"];
[txfSearchField setBackgroundColor:[UIColor whiteColor]];
    [txfSearchField setLeftView:UITextFieldViewModeNever];
    [txfSearchField setBorderStyle:UITextBorderStyleRoundedRect];
    txfSearchField.layer.borderWidth = 8.0f; 
    txfSearchField.layer.cornerRadius = 10.0f;
        txfSearchField.layer.borderColor = [UIColor clearColor].CGColor;

1
谢谢你,我总有一天会请你喝啤酒的。 - Roberto Conte Rosito
1
谢谢!我使用以下代码更改了搜索框的键盘类型: UITextField *txfSearchField = [_searchBar valueForKey:@"_searchField"]; [txfSearchField setKeyboardType:UIKeyboardTypeNumberPad]; - ThinkBonobo
@pedroremedios 将nil强制转换仍将是nil - Vignesh PT
2
它在iOS 13上崩溃了。 - ArisRS
1
在iOS 13中,您可以这样获取SearchTextField:UITextField *search = searchBar.searchTextField - BlueskyMed
显示剩余4条评论

12

如果您不想使用未记录的功能或者使用图片,请使用以下内容:

CGSize size = CGSizeMake(30, 30);
// create context with transparent background
UIGraphicsBeginImageContextWithOptions(size, NO, 1);

// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0,30,30)
                            cornerRadius:2.0] addClip];
[[UIColor whiteColor] setFill];

UIRectFill(CGRectMake(0, 0, size.width, size.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

[self.searchBar setSearchFieldBackgroundImage:image forState:UIControlStateNormal];

12

对于仍在寻找答案的人,苹果在iOS 13中向UISearchBar添加了searchTextField属性。searchTextField是从UITextField继承而来的UISeachTextField

let searchBar = UISearchBar()
var searchField : UITextField
if #available(iOS 13.0, *) {
    searchField = searchBar.searchTextField
} else {
    searchField = //One of the other methods listed
}

10

iOS 13.x & Swift 5.x:

按照以下步骤访问UISearchBar中的UITextField

extension UISearchBar {

    /// Returns the`UITextField` that is placed inside the text field.
    var textField: UITextField {
        if #available(iOS 13, *) {
            return searchTextField
        } else {
            return self.value(forKey: "_searchField") as! UITextField
        }
    }

}

6
从IOS-5开始,你可以使用外观代理(appearance proxy),参见: http://developer.apple.com/library/ios/#documentation/uikit/reference/UISearchBar_Class/Reference/Reference.html (有两个名为“Customizing Appearance”的部分,请检查两个)。
以下是一个可行的示例,它会修改应用中所有的UISearchBar:
[[UISearchBar appearance] setSearchFieldBackgroundImage:[UIImage imageNamed:@"text_box"] forState:UIControlStateNormal];
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"search_icon"] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
mysearchBar.tintColor = [UIColor whiteColor];

4

实现变更抗性和高性能

如果您正在阅读此文并且想知道如何在Swift中轻松访问搜索栏的文本字段,则可以通过使用以下代码扩展UISearchBar来添加textField属性,该代码对底层实现变更具有抗性,并缓存已找到的结果以提高性能。

import UIKit

private var foundTextFieldAssociationKey = UInt8()

extension UISearchBar {

  var textField: UITextField {
    get {
      let value = objc_getAssociatedObject(self, &foundTextFieldAssociationKey) as? UITextField

      if value == nil {
        let findInView = (UIView) -> UITextField? = { view in
          for subview in view.subviews {
            if let textField = (subview as? UITextField) ?? findInView(subview) {
              return textField
            }
          }
          return nil
        }

        guard let foundTextField = findInView(self) else {
          fatalError("UISearchBar doesn't seem to have a UITextField anywhere in the view hierarchy")
        }

        textField = foundTextField
        return foundTextField
      }

      return value!
    }
    set {
      objc_setAssociatedObject(self, &foundTextFieldAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
    }
  }

}

如果您想更改属性的名称,请确保不将其更改为 searchField。这会破坏您的搜索栏。


只返回 return self.valueForKey("_searchField") as? UITextField 如何? - ton
2
@ton 那个方法可行。我怀疑苹果不会很快更改密钥,但是当使用hacky解决方案时,我个人更喜欢找到一种对底层实现变化有点弹性的方法来解决问题。 - isair
@abishek-bedi 我把你的更改改回来了。我的代码虽然旧,但你编辑了实现的核心并将其改成了完全不同的东西。我的实现的核心在于不依赖 _searchField 以便抵抗核心实现的更改。 - isair
嘿,那是一个很棒的解决方案。苹果公司在新的集成开发环境中捕捉到了这个私有API。 - Suryanarayan Sahu

3

现在在iOS 13中,你可以使用searchTextField属性直接访问文本框。


2

简短易懂

extension UISearchBar {
    var textField:UITextField {
        guard let txtField = self.value(forKey: "_searchField") as? UITextField else {
            assertionFailure()
            return UITextField()
        }
        return txtField
    }
}

2

我发现在iOS 10上需要这样做(从上面借鉴并快速调整)

extension UISearchBar {
    var textField: UITextField? {

    func findInView(_ view: UIView) -> UITextField? {
        for subview in view.subviews {
            print("checking \(subview)")
            if let textField = subview as? UITextField {
                return textField
            }
            else if let v = findInView(subview) {
                return v
            }
        }
        return nil
      }

      return findInView(self)
    }
 }  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接