[英]Why dont some of my anchor constraints work while others do for the same item?
I am trying to put anchor constraints on a textField contained within a subView. 我试图将锚约束放到subView中包含的textField上。 For the leading and top anchors the anchors work but for the bottom and trailing anchors they dont.
对于前锚和后锚,它们不起作用。 Im not sure what it could be, I would like some space between the keyboard and the items in my subview as well as some space between the UITextField and the trailing anchor edge of the screen.
我不确定这是什么,我想在键盘和子视图中的项之间留一些空间,以及在UITextField和屏幕的尾随锚之间留一些空间。 Below is the code in question
下面是有问题的代码
Layout Code: 布局代码:
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
}
Code in its entirety 完整的代码
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)
}
}
For trailing and bottom anchor constraints, it is common that you have to use negative numbers for the constants to achieve what you want. 对于尾部和底部锚点约束,通常必须对常量使用负数才能实现所需的值。
For example: 例如:
searchBar.bottomAnchor.constraint(equalTo: myView.bottomAnchor, constant: 4).isActive = true
Becomes: 变为:
searchBar.bottomAnchor.constraint(equalTo: myView.bottomAnchor, constant: -4).isActive = true
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.