草庐IT

ios - 更新 nslayoutconstraints 以适应新的 View 大小?

coder 2023-09-15 原文

我有一个 UIView,一旦 UITextView 中的文本达到某个点,它的大小就会增加。两个 View 都在调整大小,但是我无法让 View 向上移动以适应我在 UIView 上设置的 bottomconstraint。这是问题的屏幕截图。

我已经尝试同时使用 view.setNeedsLayout()view.layoutIfNeeded() 但我假设我可能实现错误...

这是项目的代码

import UIKit

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UITextViewDelegate {


var bottomConstraint: NSLayoutConstraint?
var phconstraint: NSLayoutConstraint?

let searchBarContainer: UIView = {
    let sBarContainer = UIView()
    sBarContainer.backgroundColor = UIColor.gray
    sBarContainer.layer.cornerRadius = 3
    return sBarContainer
}()

let searchBar: UITextView = {
    let sBar = UITextView()
    sBar.textAlignment = .left
    sBar.font = .systemFont(ofSize: 12)
    sBar.backgroundColor = UIColor.red
    sBar.sizeToFit()

    return sBar
}()

let placeholder: UILabel = {
    let pholder = UILabel()

    pholder.font = UIFont.systemFont(ofSize: 16, weight: 0.20)
    pholder.frame.size = pholder.intrinsicContentSize
    pholder.backgroundColor = UIColor.clear
    pholder.textColor = UIColor.gray

    pholder.text = "Share!"

    pholder.textAlignment = .left


    return pholder
}()

let dividerLine: UIView = {
    let line = UIView()
    line.backgroundColor = UIColor.init(red: 240/255, green: 240/255, blue: 240/255, alpha: 1)
    return line
}()

let bubbleview : UIView = {
   let bView = UIView()
    bView.backgroundColor = UIColor.clear
    return bView

}()

func setupKeyboardObservers() {

    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func handleKeyboardNotification(_ notification: Notification) {

    if let userInfo = notification.userInfo {
        let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
        print(keyboardFrame as Any)

        let isKeyboardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
        let isKeybobardNotShowing = notification.name == NSNotification.Name.UIKeyboardWillHide

        bottomConstraint?.constant = isKeyboardShowing ? -keyboardFrame!.height : 0

        UIView.animate(withDuration: 0, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {

            self.view.layoutIfNeeded()
        }, completion: { (completed) in


        })
    }
}


override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = "Search Bar"
    collectionView?.backgroundColor = UIColor.white

    setupKeyboardObservers()
    self.searchBar.delegate = self    
    view.addSubview(searchBarContainer)
    searchBarContainer.addSubview(searchBar)
    searchBar.translatesAutoresizingMaskIntoConstraints = false
    searchBarContainer.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint(item: searchBarContainer, attribute: .width, relatedBy: .equal, toItem: view, attribute: .width, multiplier: 0.75, constant: 0).isActive = true

    NSLayoutConstraint(item: searchBarContainer, attribute: .height, relatedBy: .equal, toItem: view, attribute: .height, multiplier: 0.05, constant: 0).isActive = true

    NSLayoutConstraint(item: searchBarContainer, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0).isActive = true

     bottomConstraint = NSLayoutConstraint(item: searchBarContainer, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)

            view.addConstraint(bottomConstraint!)

}


func textViewDidChange(_ textView: UITextView) {
            let currentString: String = textView.text!
            let length: Int = (currentString.characters.count )

        let messageText = currentString
        let size = CGSize(width: searchBarContainer.frame.width , height: searchBarContainer.frame.height * 2)
        let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
        let estimatedFrame = NSString(string: messageText).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 12)], context: nil)
    print("this is the ewidth \(estimatedFrame.width)")
    searchBarContainer.addSubview(bubbleview)
    bubbleview.frame = estimatedFrame

    searchBar.sizeToFit()
    searchBar.frame.size.width = searchBarContainer.frame.width


            if estimatedFrame.height >= (searchBarContainer.frame.height) {

            searchBarContainer.frame.size.height = estimatedFrame.height


                self.view.addConstraint(self.bottomConstraint!)

                UIView.animate(withDuration: 0, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {

                    self.view.layoutIfNeeded()
                }, completion: { (completed) in



                })


        }
    view.setNeedsLayout()
    view.layoutIfNeeded()

}

}


extension UIView {
func addConstraintsWithFormat(_ format: String, views : UIView...) {


    var viewsDictionary = [String: UIView]()

    for(index, view) in views.enumerated(){
        let key = "v\(index)"
        viewsDictionary[key] = view
        view.translatesAutoresizingMaskIntoConstraints = false

    }
    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary))

}
}

最佳答案

几个笔记...

当尝试使用“自动调整大小”UITextView 时,您会发现如果禁用滚动效果最好...所以将其添加到您的 searchBar 设置中:

    sBar.isScrollEnabled = false

您将自动布局/约束与显式设置框架大小混合在一起。这经常会给你带来麻烦。使用一个或另一个(约束是首选方法)。在您的代码中,您设置

    searchBar.translatesAutoresizingMaskIntoConstraints = false

但你永远不会给它任何限制。

编辑:经过一番尝试后,您可以仅依靠自动布局就可以大大简化事情。

不是使用“容器” View 来保存 searchBar TextView ,而是创建一个位于 searchBar 下方的“填充” View 。然后:

  1. searchBar 应该位于 paddingView 的“顶部”
  2. paddingView 应该随着键盘向上滑动
  3. searchBar 会自动向上滑动,因为它固定在 paddingView
  4. 的顶部
  5. searchBar的高度会根据文本内容自动变化

所以 -- paddingView 将控制位置、宽度和 Y 轴位置。

你已经有了控制Y轴位置的属性

var bottomConstraint: NSLayoutConstraint?

更改searchBar定义并添加paddingView定义:

let searchBar: UITextView = {
    let sBar = UITextView()
    sBar.textAlignment = .left
    sBar.font = .systemFont(ofSize: 12)
    sBar.backgroundColor = UIColor.red
    sBar.isScrollEnabled = false
    sBar.translatesAutoresizingMaskIntoConstraints = false
    return sBar
}()

let paddingView: UIView = {
    let v = UIView()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.backgroundColor = .gray
    v.layer.cornerRadius = 3.0
    return v
}()

viewDidLoad 最终是这样的:

override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.title = "Search Bar"
    collectionView?.backgroundColor = UIColor.white
    setupKeyboardObservers()
    self.searchBar.delegate = self

    // add bottom "padding" view
    view.addSubview(paddingView)

    // add searchBar text view
    view.addSubview(searchBar)

    // set width of padding view to 75% of view width
    paddingView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.75).isActive = true
    // set center X of padding view to center X of view
    paddingView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 1.0).isActive = true
    // set height of padding view to 6.0 (we're rounding the corners with a radius of 3.0)
    paddingView.heightAnchor.constraint(equalToConstant: 6.0).isActive = true

    // assign a constraint to bottomConstraint property so we can change the Y-position of padding view (and searchBar) when desired
    // initially set the constant to 0 (so it sits on the bottom of the view)
    bottomConstraint = paddingView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0.0)
    bottomConstraint?.isActive = true

    // set searchBar width to padView width
    searchBar.widthAnchor.constraint(equalTo: paddingView.widthAnchor, multiplier: 1.0).isActive = true
    // set searchBar center X to padView center X
    searchBar.centerXAnchor.constraint(equalTo: paddingView.centerXAnchor, constant: 0.0).isActive = true
    // set searchBar bottom to padView Top + 3.0 (we want to cover the top 3 pts)
    searchBar.bottomAnchor.constraint(equalTo: paddingView.topAnchor, constant: 3.0).isActive = true
}

由于 UITextView 在使用自动布局时会自动调整自己的大小,因此您甚至不需要 textViewDidChange 函数:

func textViewDidChange(_ textView: UITextView) {
    // nothing to do here...
}

注意:我从您的 bubbleview 中只能看到它覆盖了 searchBar TextView 的一部分...所以我忽略了它。

关于ios - 更新 nslayoutconstraints 以适应新的 View 大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44247741/

有关ios - 更新 nslayoutconstraints 以适应新的 View 大小?的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  5. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  6. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  7. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  8. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  9. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  10. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

随机推荐