更新nslayoutconstraints以适应新的视图大小?

时间:2017-05-29 17:26:25

标签: ios swift nslayoutconstraint

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

before the view is resized

after the view is resized

我尝试过同时使用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))

}
}

3 个答案:

答案 0 :(得分:2)

情侣笔记......

尝试使用“自动调整大小”UITextView时,如果禁用滚动功能,则会发现效果最佳...因此请将其添加到searchBar设置中:

    sBar.isScrollEnabled = false

您正在混合使用显式设置帧大小的自动布局/约束。这常常让你陷入困境。使用一个或另一个(约束是首选方法)。在您的代码中,您设置

    searchBar.translatesAutoresizingMaskIntoConstraints = false

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

编辑:在玩了一下之后,你可以通过依靠自动布局来大大简化一些事情。

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

  1. searchBar应位于“paddingView
  2. 之上
  3. paddingView应使用键盘向上滑动
  4. searchBar会自动向上滑动,因为它固定在paddingView的顶部
  5. searchBar的高度将根据文字内容自动更改
  6. 所以 - 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...
    }
    

    enter image description here

    enter image description here

    注意:我从bubbleview看到的只是它覆盖了searchBar文字视图的一部分...所以我忽略了它。

答案 1 :(得分:0)

只需使用 stackview

  1. 将textView包装到stackView
  2. 为stackView拉出必要的布局约束。
  3. 从属性检查器中使TextView不可滚动。当textView文本增加时,textView会向上增加。

答案 2 :(得分:0)

在致电textView

后更新sizeToFit()布局
searchBar.sizeToFit()
searchBar.frame.size.width = searchBarContainer.frame.width
searchBar.setNeedsLayout()