UISearchbar文本框的高度可以修改吗?

45

我正在测试我的用户界面,发现搜索栏有点太窄,想要将其高度调整一下。同时,我也希望视力较差或手部协调能力较差的人们不会在使用时遇到任何问题。

因此,我想要做的是调整UISearchbar中的UITextField的高度。

我尝试过以下方法:

  1. 在Storyboard中添加UISearchbar高度约束——结果:搜索栏大小增加了,但是里面的UITextField大小没有改变。
  2. 访问UISearchbar中的UITextField并修改其高度——结果:控制台输出显示已经修改了参数,但是屏幕上UITextField的高度仍然保持不变。

注意:我可以使用第二种方法修改UITextField的其他参数,并在屏幕上反映出变化,所以我知道我已经访问到了UITextField

Method 2的代码,在包含UISearchbar的ViewController的viewDidLoad()中:

for tempView in (self.roomInfoSearchBar.subviews[0] as! UIView).subviews as! [UIView]
{
  if let tV = tempView as? UITextField
  {
    var currentFrameRect = tV.frame
    currentFrameRect.size.height = 80
    //tV.layer.backgroundColor = UIColor.blueColor().CGColor  //This works fine
    //tV.layer.cornerRadius = 5  //This works fine
    //tV.font = UIFont(name: "Courier", size: 40)  //This works fine
    println(tV.frame.height)  //console output:0.0
    tV.frame = currentFrameRect
    println(tV.frame) //console output:(0.0, 0.0, 0.0, 80.0)
    println(currentFrameRect) //console output:(0.0, 0.0, 0.0, 80.0) - redundant, just checking
    println(tV.frame.height) //console output:80.0 - it says 80, but screen shows searchbar definitely not 80.
  }
}
我认为这与自动布局有关,它可以在任何位置忽略参数。我想继续使用自动布局,因为它可以为我完成很多工作,但我希望它的行为类似于Storyboard中的行为,即当用户设置一个选项时,它将在其自动布局中使用这些参数,并在无法使用时提供反馈,而不是无声地忽略它。 编辑: 回应Mahesh的评论。我不太懂Objective C ++,但我尽力将您写的内容转换成Swift语言。以下是我的代码(位于viewcontroller.swift内部):
func viewDIdLayoutSubviews()
{
  super.viewDidLayoutSubviews()
  self.roomInfoSearchBar.layoutSubviews()

  var topPadding: Float = 5.0
  for view in (self.roomInfoSearchBar.subviews[0] as! UIView).subviews as! [UIView]
  {
    if let tfView = view as? UITextField
    {
      var calcheight = self.roomInfoSearchBar.frame.size.height - 10
      tfView.frame = CGRectMake(tfView.frame.origin.x, CGFloat(topPadding), tfView.frame.size.width, self.roomInfoSearchBar.frame.size.height - CGFloat(topPadding * 2))
    }
  }
}

由于我在将你的代码转换成Swift时遇到一些问题,所以我保留了获取文本字段的代码。对于CGRectMake - Swift抱怨包括topPadding不是CGFloat类型,对于最后一个变量(Y大小),它也不喜欢将CGFloat与Float混合,因此我也不得不改变它。

不幸的是,它似乎并不起作用。 我在Storyboard中将UISearchbar的高度更改为80,但只得到一个非常高的搜索栏,而文本字段仅覆盖总高度的1/3。

编辑#2:结合Yuyutsu和Mahesh代码的修正版。 仍然不完美,但更接近了。 Yuyutsu的代码有效,但如我在评论中提到的那样,该字段没有居中,当视图首次加载时,调整大小也可见(从高度A跳到高度B)。 另一个缺点是,因为调整大小是在viewDidAppear中完成的,所以一旦方向发生变化,该字段就会返回固有大小。

基于Yuyutsu的我的代码:

  override func viewDidAppear(animated: Bool)
  {
    super.viewDidAppear(animated)
    var roomInfoSearchBarFrame = roomInfoSearchBar.frame
    var newHeight: CGFloat = 60
    for subView in roomInfoSearchBar.subviews
    {
      for subsubView in subView.subviews
      {
        if let textField = subsubView as? UITextField
        {
          var currentTextFieldFrame = textField.frame
          var recenteredY = (roomInfoSearchBarFrame.height - newHeight)/2
          var newTextFieldFrame = CGRectMake(textField.frame.minX, recenteredY, textField.frame.width, newHeight)

          textField.frame = newTextFieldFrame
          textField.borderStyle = UITextBorderStyle.RoundedRect
          textField.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
          //textField.backgroundColor = UIColor.redColor()
          //                    textField.font = UIFont.systemFontOfSize(20)
        }
      }
    }
  }

查看Yuyutsu的代码后,我想知道在哪里可以放置此调整项,然后我通过另一个stackoverflow帖子发现了链接。根据我的阅读,我认为Mahesh的答案应该可以解决问题。这就是我意识到为什么它没有起作用的地方 - 我需要覆盖func viewWillLayoutSubviews()

当前代码:与方向更改一起保持大小。 但是大小跳跃仍然可见(不应该可见)

  override func viewWillLayoutSubviews()
  {
    super.viewWillLayoutSubviews()
    var roomInfoSearchBarFrame = roomInfoSearchBar.frame
    var newHeight: CGFloat = 60
    for subView in roomInfoSearchBar.subviews
    {
      for subsubView in subView.subviews
      {
        if let textField = subsubView as? UITextField
        {
          var currentTextFieldFrame = textField.frame
          var recenteredY = (roomInfoSearchBarFrame.height - newHeight)/2
          var newTextFieldFrame = CGRectMake(textField.frame.minX, recenteredY, textField.frame.width, newHeight)

          textField.frame = newTextFieldFrame
          textField.borderStyle = UITextBorderStyle.RoundedRect
          textField.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
          //textField.backgroundColor = UIColor.redColor()
          //                    textField.font = UIFont.systemFontOfSize(20)
        }
      }
    }
  }

目前,唯一剩下的就是尝试使文本字段在视图可见之前成为设置大小,以便对用户不可见。

最终编辑:完全工作的代码在Yuyutsu的额外帮助下,下面的代码可以做到我想要的一切-从设置大小开始,字段居中,处理旋转也很好。

  override func viewDidLayoutSubviews()
  {
    super.viewDidLayoutSubviews()
    self.roomInfoSearchBar.layoutIfNeeded()
    self.roomInfoSearchBar.layoutSubviews()

    var roomInfoSearchBarFrame = roomInfoSearchBar.frame
    var newHeight: CGFloat = 60 //desired textField Height.
    for subView in roomInfoSearchBar.subviews
    {
      for subsubView in subView.subviews
      {
        if let textField = subsubView as? UITextField
        {
          var currentTextFieldBounds = textField.bounds
          currentTextFieldBounds.size.height = newHeight
          textField.bounds = currentTextFieldBounds
          textField.borderStyle = UITextBorderStyle.RoundedRect
          //textField.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
        }
      }
    }
  }

感谢Yuyutsu。 Mahesh感谢你基本上从一开始就提出了最终解决方案,只是缺少一些关键部分。


通过使用Mahesh的填充想法,最终可以更加方便。基本上,您可以根据roomInfoSearchBar.frame减去2 * somePadding(somePadding是您希望在searchField和textField之间留出的空间)来计算newHeight。一旦设置了这个,您就可以在Storyboard中调整searchBar大小,textField也会相应调整。如果您想更改填充,则只需要修改viewDidLayoutSubviews()即可。 - janson
1
最好的解决方案是使用 UITextField,并将放大镜图像添加到其 leftView 中。实际上,这样做可以避免因为对 UISearchBar 进行修改而导致的很多问题。 - Sulthan
感谢大家,我已经使用你们的最终代码解决了问题。 - Ilesh P
未能在iOS 11/Swift 4上工作。 - Bogdan Razvan
检查我的答案。仍在工作中... - WR-BikAir
最后一个解决方案中的roomInfoSearchBarFrame变量似乎从未被使用。 - scaly
9个回答

18
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        for subView in searchBars.subviews  {
            for subsubView in subView.subviews  {
                if let textField = subsubView as? UITextField {
                     var bounds: CGRect
                bounds = textField.frame
                bounds.size.height = 35 //(set height whatever you want)
                    textField.bounds = bounds
                    textField.borderStyle = UITextBorderStyle.RoundedRect
//                    textField.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
                    textField.backgroundColor = UIColor.redColor()
//                    textField.font = UIFont.systemFontOfSize(20)
                }
            }
        }

    }

这可能对你有所帮助 :)


1
是的,你的代码确实改变了文本框本身的大小,这对我来说是很大的进步!=D。我猜Autolayout在viewDidLoad之后但在viewDidAppear之前完成它的工作。这种方法的唯一问题是我看到了调整大小的发生 - 即视图加载时具有Autolayout内在大小,然后突然更改为frame.size.height中指定的大小。我尝试将其放在viewWillAppear中以查看,但是那时字段处于内在大小。我应该能够解决的另一个小问题是该字段未居中在搜索栏中。 - janson
嘿,改用 textfield.bounds 而不是 frame。我已经更新了答案。让我知道它对我是否有效。 - Yuyutsu
嘿,将我的代码添加到 viewDidLayoutSubviews 中,并添加以下内容 self.searchBars.layoutIfNeeded() self.searchBars.layoutSubviews() - Yuyutsu
https://dev59.com/fV8d5IYBdhLWcg3wmDOf?answertab=oldest#tab-top - Yuyutsu
1
你最后的修改起了作用。最终,像Mahesh最初建议的那样,在viewDidLayoutSubviews中完成了,但我想这两行代码也是必要的(layoutIfNeededlayoutSubviews)。为了完整起见,我将编辑我的问题以涵盖这个最终工作的版本。再次感谢你。 - janson
显示剩余2条评论

15

如果你使用:

func setSearchFieldBackgroundImage(backgroundImage: UIImage?, forState state: UIControlState)   

UISearchBar的UITextfield高度将与图像的高度相同。

您可以插入一张图片,使用它来自定义UISearchBar的UITextfield高度和背景图像。

或者您可以使用下面的函数创建圆角UIImage:

func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    let rect = CGRectMake(0, 0, size.width, size.height)
    let path = UIBezierPath(roundedRect: rect, cornerRadius: 5.0)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    path.fill()
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

UIImage的宽度被忽略。但为了拥有圆角,最好大于10.0

代码将会如下所示:

let image = self.getImageWithColor(UIColor.lightGrayColor(), size: CGSizeMake(20, 20))
searchBar.setSearchFieldBackgroundImage(image, forState: .Normal)

运行得很好。在以前的解决方案中编辑文本时,搜索栏高度会“抖动”。 - djserva
这是我在网上找到的所有答案中最干净、最好的方式。 - zero3nna
很遗憾,你现在使用这种方法会出现错误:'UIGraphicsBeginImageContext Usage Violation: Should use UIGraphicsImageRenderer instead'。所以我认为这个方法需要刷新一下了。我会试着修改一下看看能否让它正常工作。 - johnny

8
这是关于如何改变UISearchBar高度的正确Swift 4.0答案:

  let image = getImageWithColor(color: UIColor.clear, size: CGSize(width: 1, height: 40))
  searchBar.setSearchFieldBackgroundImage(image, for: .normal)

使用以下方法:

  func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        color.setFill()
        UIRectFill(rect)
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }

测试于2018年6月4日


8

根据thelearner的回答,这是Swift 5.*的代码:

extension UISearchBar {
    func updateHeight(height: CGFloat, radius: CGFloat = 8.0) {
        let image: UIImage? = UIImage.imageWithColor(color: UIColor.clear, size: CGSize(width: 1, height: height))
        setSearchFieldBackgroundImage(image, for: .normal)
        for subview in self.subviews {
            for subSubViews in subview.subviews {
                if #available(iOS 13.0, *) {
                    for child in subSubViews.subviews {
                        if let textField = child as? UISearchTextField {
                            textField.layer.cornerRadius = radius
                            textField.clipsToBounds = true
                        }
                    }
                    continue
                }
                if let textField = subSubViews as? UITextField {
                    textField.layer.cornerRadius = radius
                    textField.clipsToBounds = true
                }
            }
        }
    }
}

private extension UIImage {
    static func imageWithColor(color: UIColor, size: CGSize) -> UIImage? {
        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        color.setFill()
        UIRectFill(rect)
        guard let image: UIImage = UIGraphicsGetImageFromCurrentImageContext() else {
            return nil
        }
        UIGraphicsEndImageContext()
        return image
    }
}

以下是如何应用它的方法:

searchBar?.updateHeight(height: 48)

以下是结果: 图片描述在此输入


5

我发现被接受的答案有时存在问题。
这是我解决搜索栏具有自定义高度问题的方法。在viewDidLoad中,我设置了一个大小与所需高度相同的彩色图像并将其添加到搜索栏的文本框中:

let image = getImageWithColor(UIColor.whiteColor(), size: CGSizeMake(600, 60))
searchBar.setSearchFieldBackgroundImage(image, forState: .Normal)

接下来是从这里取得的函数

func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
    var rect = CGRectMake(0, 0, size.width, size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    var image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

关闭图标仍然很小?没有调整大小。 - Ramesh Kumar

2

您可以更改内部文本字段的高度,尝试此代码。

步骤1)设置约束以增加您的UISearchBar高度,然后将搜索栏的出口制作为视图控制器中的代码,并编写以下代码。

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    [self.searchBar layoutSubviews];

    float topPadding = 5.0;
    for(UIView *view in self.searchBar.subviews)
    {
        for(UITextField *textfield in view.subviews)
        {
            if ([textfield isKindOfClass:[UITextField class]]) {
                textfield.frame = CGRectMake(textfield.frame.origin.x, topPadding, textfield.frame.size.width, (self.searchBar.frame.size.height - (topPadding * 2)));
            }
        }
    }
}

如果您想修改搜索栏中的其他内容,可以在UITextField的子视图中找到确切的基本元素,如UILabel、UIImage和UIView,并更改frame、image和其他属性。感谢。
编辑:根据您的要求,我将其用Swift编写。我认为您可能在尝试错误的操作,请尝试此方法。
func viewDIdLayoutSubviews()
{
    super.viewDidLayoutSubviews()
    self.roomInfoSearchBar.layoutSubviews()

    var topPadding: Float = 5.0
    for view in self.roomInfoSearchBar.subviews as [UIView] 
    {
        for viewNew in view.subviews as [UIView] 
        {
            if viewNew.isKindOfClass(UITextField) 
            {
                viewNew.frame = CGRectMake(viewNew.frame.origin.x, CGFloat(topPadding), viewNew.frame.size.width, self.roomInfoSearchBar.frame.size.height - CGFloat(topPadding * 2))
            }
        }
    }
}

你将0索引视图作为循环的第一个和最后一个视图。我认为这就是你翻译的代码无法工作的问题所在。请尝试一次并回复。


我尝试将你的建议翻译成Swift。我认为我已经正确地翻译了,但是内部的文本框仍然保持原来的高度。 - janson
请查看我编辑过的答案,并且请使用我编辑过的代码。 - Mahesh Agrawal
你之前使用了 self.roomInfoSearchBar.subviews[0],这是不正确的。文本框可以在任何视图中,而这些视图又可能是 UISearchBar 的任何子视图。你不能假设它一定在索引为 0 的视图中。 - Mahesh Agrawal
实际上我不确定它会出现在哪个子视图中,所以我将所有视图都放在循环中。 - Mahesh Agrawal
但是你的两个循环的目的是为了定位UITextField,以便可以修改它的设置,对吧?由于textfield是子视图的子视图,所以需要两个循环。我使用self.roomInfoSearchBar.subviews[0],因为通过实验我知道那里是UITextField被埋藏的地方。本质上,我认为我们都到达了同样的地方,然后我尝试使用CGRectMake来绘制完整的框架,就像你建议的那样(而不仅仅是设置高度),但是textfield的高度没有改变。刚看到你的Swift版本...会试一下。谢谢。 - janson
显示剩余2条评论

1
对于Swift 5.0,它运行良好:

extension UIImage {
    class func image(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            color.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
}

extension UISearchBar {
    func customize() {
        setSearchFieldBackgroundImage(UIImage.image(color: .clear, size: CGSize(width: 1, height: 44)), for: .normal)

        // other settings
        searchBarStyle = .minimal
        searchTextPositionAdjustment = UIOffset(horizontal: 0, vertical: 0)
        tintColor = .black
        backgroundColor = .whiteBackground
        searchTextField.leftViewMode = .never
        searchTextField.textColor = .black
        searchTextField.backgroundColor = UIColor.lightGrayBackground
        searchTextField.layer.borderColor = UIColor.gray.cgColor
        searchTextField.cornerRadius = 22
        searchTextField.borderWidth = 0.5
    }
}

只需使用:

let searchBar = UISearchBar()
searchBar.customize()

0

wj2061的MonoTouch版本答案:

UIImage GetImageWithColor(UIColor color, CGSize size)
{
    var rect = new CGRect(0, 0, size.Width, size.Height);
    var path = UIBezierPath.FromRoundedRect(rect, 5);
    UIGraphics.BeginImageContextWithOptions(size, false, 0);
    color.SetFill();
    path.Fill();
    var image = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    return image;
}

var image = GetImageWithColor(UIColor.LightGray, new CGSize(20, 20));
searchBar.SetSearchFieldBackgroundImage(image, UIControlState.Normal);

0

更新至Swift 4.2/iOS 12.1:

let newHeight : CGFloat = 45
for subview in searchBar.subviews {
    for subsubview in subview.subviews {
        if let textField = subsubview as? UITextField {
            var currentTextfieldBounds = textField.bounds
            currentTextfieldBounds.size.height = newHeight
            textField.bounds = currentTextfieldBounds
            textField.borderStyle = .roundedRect
            textField.contentVerticalAlignment = .center
        }
    }
}

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