为什么我的某些锚约束不起作用,而其他锚约束对同一项目起作用?

Why dont some of my anchor constraints work while others do for the same item?

我正在尝试对包含在子视图中的 textField 设置锚点约束。对于前锚和顶部锚,锚起作用,但对于底部和尾随锚,它们不起作用。我不确定它可能是什么,我想要在键盘和我的子视图中的项目之间有一些 space 以及在 UITextField 和屏幕的尾随锚边缘之间有一些 space 。下面是有问题的代码

布局代码:

func setUpLayout(){

    //myView
    self.myView.translatesAutoresizingMaskIntoConstraints = false
    self.myView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
  self.myView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
    self.myView.heightAnchor.constraint(equalToConstant: 98).isActive = true
    self.myView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 4).isActive = true


    //CollectionView
    self.collectionView.translatesAutoresizingMaskIntoConstraints = false
    self.collectionView.leadingAnchor.constraint(equalTo: self.myView.leadingAnchor, constant: 0).isActive = true
    self.collectionView.trailingAnchor.constraint(equalTo: self.myView.trailingAnchor, constant: 0).isActive = true
    self.collectionView.bottomAnchor.constraint(equalTo: self.myView.bottomAnchor, constant: 4).isActive = true
    self.collectionView.topAnchor.constraint(equalTo: self.searchBar.bottomAnchor, constant: 4).isActive = true

    //searchbar
    self.searchBar.translatesAutoresizingMaskIntoConstraints = false
    self.searchBar.topAnchor.constraint(equalTo: self.myView.topAnchor, constant: 0).isActive = true
    self.searchBar.leadingAnchor.constraint(equalTo: self.myView.leadingAnchor, constant: 4).isActive = true
    self.searchBar.trailingAnchor.constraint(equalTo: self.myView.trailingAnchor, constant: 4).isActive = true
    self.searchBar.heightAnchor.constraint(equalToConstant: 45).isActive = true
    searchBar.backgroundColor = .white
    searchBar.layer.borderWidth = 2
    searchBar.layer.borderColor = UIColor.black.cgColor
    //PictureView
    self.PictureView.translatesAutoresizingMaskIntoConstraints = false
    self.PictureView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
    self.PictureView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    self.PictureView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
    self.PictureView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
    self.PictureView.backgroundColor = .green
}

完整代码

import UIKit

class SearchCollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout, UITextFieldDelegate, UICollectionViewDataSource,UIGestureRecognizerDelegate {

    var myView: UIView!
    var searchBar: UITextField!
    var collectionView: UICollectionView!

    var PictureView: UIView!


    var genericArray:[String] = ["A","B","C","D","E","F","G","Ab","Abc","za"]
    var currentGenericArray:[String] = [String]()
    var tagsSelected:[String] = [String]()


    let keyboardSlider = KeyboardSlider()

    override func viewDidLoad() {
        super.viewDidLoad()
        keyboardSlider.subscribeToKeyboardNotifications(view: view)

        myView = UIView(frame: CGRect(x: 0, y: self.view.frame.height, width: self.view.frame.width, height: self.view.frame.height))
        searchBar = UITextField(frame: CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.myView.frame.height))
        PictureView = UIView(frame: self.view.frame)
         self.view.addSubview(PictureView)

        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: (UIScreen.main.bounds.width-1)/2, height: (UIScreen.main.bounds.width-1)/2)
        layout.scrollDirection = .horizontal
        self.collectionView = UICollectionView(frame: CGRect(x: 0, y: self.myView.frame.height, width: self.myView.frame.width, height: 100), collectionViewLayout: layout)
        collectionView.backgroundColor = .clear
        collectionView.contentInset = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
        myView.backgroundColor = .clear
        collectionView.delegate = self
        collectionView.dataSource = self
        self.myView.addSubview(collectionView)
        self.view.addSubview(myView)

        collectionView.register(CollectionCell.self, forCellWithReuseIdentifier: "collectionViewCell")
        currentGenericArray = genericArray




        searchBar.delegate = self
        searchBar.autocorrectionType = .no
        searchBar.keyboardType = .default
        searchBar.addTarget(self, action: #selector(SearchCollectionViewController.textFieldDidChange), for: .editingChanged)



        self.myView.addSubview(searchBar)


        let viewTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(gestureRecognizer:)))
        viewTapGestureRecognizer.cancelsTouchesInView = false
        self.PictureView.addGestureRecognizer(viewTapGestureRecognizer)
        self.PictureView.backgroundColor = .purple
        self.view.backgroundColor = .green
        self.searchBar.becomeFirstResponder()

        self.collectionView.allowsSelection = true
        setUpLayout()
    }

    func setUpLayout(){

        //myView
        self.myView.translatesAutoresizingMaskIntoConstraints = false
        self.myView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
      self.myView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        self.myView.heightAnchor.constraint(equalToConstant: 98).isActive = true
        self.myView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 4).isActive = true


        //CollectionView
        self.collectionView.translatesAutoresizingMaskIntoConstraints = false
        self.collectionView.leadingAnchor.constraint(equalTo: self.myView.leadingAnchor, constant: 0).isActive = true
        self.collectionView.trailingAnchor.constraint(equalTo: self.myView.trailingAnchor, constant: 0).isActive = true
        self.collectionView.bottomAnchor.constraint(equalTo: self.myView.bottomAnchor, constant: 4).isActive = true
        self.collectionView.topAnchor.constraint(equalTo: self.searchBar.bottomAnchor, constant: 4).isActive = true

        //searchbar
        self.searchBar.translatesAutoresizingMaskIntoConstraints = false
        self.searchBar.topAnchor.constraint(equalTo: self.myView.topAnchor, constant: 0).isActive = true
        self.searchBar.leadingAnchor.constraint(equalTo: self.myView.leadingAnchor, constant: 4).isActive = true
        self.searchBar.trailingAnchor.constraint(equalTo: self.myView.trailingAnchor, constant: 4).isActive = true
        self.searchBar.heightAnchor.constraint(equalToConstant: 45).isActive = true
        searchBar.backgroundColor = .white
        searchBar.layer.borderWidth = 2
        searchBar.layer.borderColor = UIColor.black.cgColor
        //PictureView
        self.PictureView.translatesAutoresizingMaskIntoConstraints = false
        self.PictureView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        self.PictureView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
        self.PictureView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        self.PictureView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        self.PictureView.backgroundColor = .green
    }



    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

    }



    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        keyboardSlider.unsubscribeFromKeyboardNotifications()

    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()

        collectionView.reloadData()
        return true
    }

    /// Helper to dismiss keyboard
    @objc func didStopEditing() {
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        UIView.setAnimationCurve(UIViewAnimationCurve.easeInOut)
        UIView.animate(withDuration: 0.2) {
            self.view.frame.origin.y = 0
        }
    }

    @objc func textFieldDidChange(){
        guard(!(searchBar.text?.isEmpty)!) else{
            currentGenericArray = genericArray
            collectionView.reloadData()
            return
        }

        currentGenericArray = genericArray.filter({letter -> Bool in
            if searchBar.text!.count > letter.count{
                return false
            }
            let stringRange = letter.index(letter.startIndex, offsetBy: searchBar.text!.count)
            let subword = letter[..<stringRange]
            return subword.lowercased().contains(searchBar.text!.lowercased())
        })

        if currentGenericArray.isEmpty{
            print("text being inserted \(searchBar.text!)")
            currentGenericArray.append(searchBar.text!)
        }

        collectionView.reloadData()
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if (touch.view?.isDescendant(of: self.collectionView))!{
            return false
        }
        return true
    }

    var keyboardIsOpen:Bool = false

    @objc func viewTapped(gestureRecognizer:UIGestureRecognizer){

        if keyboardIsOpen{
            myView.isHidden = true
            keyboardIsOpen = !keyboardIsOpen
            searchBar.resignFirstResponder()
        }

        else{
            myView.isHidden = false
            keyboardIsOpen = !keyboardIsOpen
            searchBar.becomeFirstResponder()
        }


    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if section == 0{
            return tagsSelected.count
        }
        else {
            return currentGenericArray.count
        }
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionCell
        if indexPath.section == 0{
            cell.collectionLabel.text = tagsSelected[indexPath.item]
            cell.backgroundColor = .blue
            cell.collectionLabel.textColor = .white
        }
        else if indexPath.section == 1{
            cell.backgroundColor = .white
            cell.collectionLabel.textColor = UIColor.black
            cell.collectionLabel.text = currentGenericArray[indexPath.row]
        }
        cell.layer.masksToBounds = true
        cell.layer.cornerRadius = cell.bounds.width/20
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 6
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        if indexPath.section == 1{\
            if(tagsSelected.contains(currentGenericArray[indexPath.item])){
            }

            tagsSelected.append(currentGenericArray[indexPath.item])
            for i in 0...genericArray.count-1{
                if(currentGenericArray[indexPath.item] == genericArray[i]){
                    genericArray.remove(at: i)
                    break
                }
            }
            currentGenericArray.remove(at: indexPath.item)
            searchBar.text = ""
            collectionView.reloadData()
            if collectionView.numberOfItems(inSection: 1)>0{
            collectionView.scrollToItem(at: IndexPath(item: 0, section: 1), at: .right, animated: true)
            }
        }
        else if indexPath.section == 0{
            currentGenericArray.append(tagsSelected[indexPath.item])
            tagsSelected.remove(at: indexPath.item)
            collectionView.reloadData()
        }
    }

    var offsetY:CGFloat = 0

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        NotificationCenter.default.addObserver(self, selector: #selector(SearchCollectionViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
    }



    @objc func keyboardFrameChangeNotification(notification: Notification) {
        if let userInfo = notification.userInfo {
            let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect
            let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0
            let animationCurveRawValue = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int) ?? Int(UIViewAnimationOptions.curveEaseInOut.rawValue)
            let animationCurve = UIViewAnimationOptions(rawValue: UInt(animationCurveRawValue))
            if let _ = endFrame, endFrame!.intersects(self.myView.frame) {
                self.offsetY = self.myView.frame.maxY - endFrame!.minY
            } else {
                if self.offsetY != 0 {
                    UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
                        self.myView.frame.origin.y = self.myView.frame.origin.y + self.offsetY
                        self.offsetY = 0
                    }, completion: nil)
                }
            }
        }
    }

}


class CollectionCell:UICollectionViewCell{


    var collectionLabel: UILabel!
    var view:UIView!
    override init(frame: CGRect) {
        super.init(frame: frame)
         collectionLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height))
        self.addSubview(collectionLabel)
        collectionLabel.textAlignment = .center
        collectionLabel.translatesAutoresizingMaskIntoConstraints = false
        collectionLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
        collectionLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
        collectionLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
        collectionLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension UIView {
    func currentFirstResponder() -> UIResponder? {
        if self.isFirstResponder {
            return self
        }

        for view in self.subviews {
            if let responder = view.currentFirstResponder() {
                return responder
            }
        }

        return nil
    }
}

extension Notification.Name{
    static let showKeyboard = Notification.Name("showKeyboard")
}
class KeyboardSlider: NSObject {
    // variables to hold and process information from the view using this class
    weak var view: UIView?

    @objc func keyboardWillShow(notification: NSNotification) {
        // method to move keyboard up
        view?.frame.origin.y = 0 - getKeyboardHeight(notification as Notification)
    }

    func getKeyboardHeight(_ notification:Notification) -> CGFloat {
        // get exact height of keyboard on all devices and convert to float value to return for use
        let userInfo = notification.userInfo
        let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
        return keyboardSize.cgRectValue.height
    }

    func subscribeToKeyboardNotifications(view: UIView) {
        // assigning view to class' counterpart
        self.view = view
        // when UIKeyboardWillShow do keyboardWillShow function
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
    }

    func unsubscribeFromKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
    }


}

对于尾部和底部锚点约束,通常必须使用负数作为常量才能实现您想要的效果。

例如:

searchBar.bottomAnchor.constraint(equalTo: myView.bottomAnchor, constant: 4).isActive = true

变为:

searchBar.bottomAnchor.constraint(equalTo: myView.bottomAnchor, constant: -4).isActive = true