【问题标题】:Can the height of the UISearchbar TextField be modified?UISearchbar TextField 的高度可以修改吗?
【发布时间】:2015-06-16 04:44:01
【问题描述】:

我正在测试我的 UI,我发现搜索栏有点太窄了,我不喜欢。我还想确保视力较差或手动灵活性较差的人在调出他们想要的界面时不会遇到问题。

所以,我想做的是调整UITextfieldUISearchbar 内的高度。

我尝试过的: 1. 在 Storyboard 中,添加UISearchbar 高度约束 - 结果:搜索栏大小增加,但里面的UITextField 保持不变。

  1. 访问UISearchbar 中的UITextField 并修改其高度 - 结果:控制台输出显示参数已修改,但在屏幕上,UITextField 高度保持不变。

注意 - 我可以使用方法 2 修改 UITextField 的其他参数,并且更改会反映在屏幕上,所以我知道我正在访问 UITextField

方法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 中一样,当用户设置设置时,它会在其自动布局中使用这些参数并在可以时抱怨' t 而不是在没有反馈的情况下忽略设置。

编辑:

回应马赫什。我不太了解客观的 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 的代码有效,但正如我的 cmets 中所述,该字段不居中,第一次加载视图时,调整大小也是可见的(从高度 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 帖子遇到了link。根据我阅读的内容,我看到 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
        }
      }
    }
  }

谢谢悠悠。 感谢 Mahesh 从一开始就提出了最终解决方案,只是遗漏了一些关键部分。

【问题讨论】:

  • Final 可以通过使用 Mahesh 的填充思想更加方便。本质上,您根据 roomInfoSearchBar.frame 减去 2 * somePadding(somePadding 是您想要的 searchField 和 textField 之间的空间)计算 newHeight。一旦你设置好了,你就可以在 Storyboard 中调整 searchBar 的大小,文本字段也会随之调整。如果要更改填充,只需修改viewDidLayoutSubviews()即可。
  • 最好的解决方案是使用UITextField 并将放大镜图像添加到其leftView。真的,你会解决很多入侵UISearchBar引起的问题。
  • 感谢我使用您的最终代码修复的所有问题。
  • 不适用于 iOS11/swift 4。
  • 检查我的答案。还在工作...

标签: swift autolayout uisearchbar


【解决方案1】:
    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)
                }
            }
        }

    }

这可能对你有帮助:)

【讨论】:

  • 是的,您的代码确实改变了文本字段本身的大小,这对我来说是一个很大的进步! =D。我猜 Autolayout 在viewDidLoad 之后但在viewDidAppear 之前做它的事情。这种方法的唯一问题是我看到发生了调整大小 - 即视图以 Autolayout 固有大小加载,然后突然变为frame.size.height 中指示的大小。我尝试将其放入 viewWillAppear 只是为了查看,但随后该字段处于固有大小。我应该能够解决的其他小问题是该字段未在搜索栏中居中。
  • 嘿,更改 textfield.bounds 而不是 frame。我更新答案。让我知道它对我来说很好
  • 更改边界确实有助于消除对居中代码的需要。剩下的唯一问题是调整大小对用户可见。不幸的是 viewDidAppear 在屏幕绘制过程中为时已晚。即使在willLayoutSubviews 中,重绘仍然可见。
  • 嘿,将我的代码添加到viewDidLayoutSubviews 并添加这些self.searchBars.layoutIfNeeded() self.searchBars.layoutSubviews()
  • 您的最终修改成功了。最后它在 viewDidLayoutSubviews 中,正如 Mahesh 最初建议的那样,但我想这两行也是需要的(layoutIfNeededlayoutSubviews)。为了完整起见,我将编辑我的问题以涵盖最后的工作问题。再次感谢您。
【解决方案2】:

如果你使用:

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

UISearchBar 的 UITextfield 的高度将与 Image 的高度相同。

你可以放入一个Image,用它来自定义UISearchBar的UITextfield高度和backgroundImage。

或者你可以使用下面的函数来创建一个圆角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 的 Width 被忽略了。但是要有一个圆角半径,最好比10.0 大。

代码如下所示:

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

【讨论】:

  • 作为一个魅力。在以前的解决方案上编辑文本时,搜索栏高度会“闪烁”。
  • 这确实是我在网上找到的所有答案中最干净、最好的方法。
  • 不幸的是,您现在使用此方法会收到此错误:UIGraphicsBeginImageContext Usage Violation: Should use UIGraphicsImageRenderer instead。所以我认为这种方法需要刷新。我会乱来看看能不能让它工作。
【解决方案3】:

这是关于如何更改 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
    }

4 日测试。六月。 2018

【讨论】:

    【解决方案4】:

    基于 thelearner's answer 这是 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?.setSearchTextField(height: 48)
    

    结果如下:

    【讨论】:

      【解决方案5】:

      我发现接受的答案有时有问题。
      这就是我解决搜索栏自定义高度问题的方法:我设置了一个具有我想要大小的彩色图像,并将其添加到 viewDidLoad 中的搜索栏文本字段中:

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

      接着这个函数取自here

      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
      }
      

      【讨论】:

      • 关闭图标还是小?不调整大小
      【解决方案6】:

      您可以更改内部文本字段的高度试试这个代码。

      步骤 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)));
                  }
              }
          }
      }
      

      如果您想更改搜索栏中的其他任何内容,您可以找到确切的基本元素,例如 UILabelUIImageUIView UITextField subviews 里面可以改变frameimageother 属性也。谢谢。

      编辑:

      正如您在 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。我想我翻译正确,但里面的文本字段仍然是原始高度。
      • 查看我编辑的答案,请使用我编辑过的确切代码。
      • 您使用了 self.roomInfoSearchBar.subviews[0] 这是不正确的。文本字段可以在 UISearchBar 的任何子视图中的任何视图中。您不能假设它在索引 0 处进入视图。
      • 实际上我不确定它来自哪个子视图,这就是为什么我将所有视图都放入 for 循环中。
      • 但是您的两个循环的重点是定位 UITextField 以便可以修改其设置对吗?需要两个循环,因为文本字段是子视图的子视图。我使用 self.roomInfoSearchBar.subviews[0] 因为从实验中我知道那是 UITextField 被埋葬的地方。本质上我认为我们都到了同一个地方,然后我尝试使用 CGRectMake 来绘制整个框架建议(而不仅仅是设置高度),但文本字段的高度不会改变。刚刚看到你的 swift 版本......会试试看。谢谢。
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        对于 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()
        

        【讨论】:

          【解决方案9】:

          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);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-03-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-13
            • 2018-10-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多