Предупреждение о макете UIButtonBarButton при вводе UITextView на iPad, а не на iPhone

#layout #uikit #uitextview #swift5

#макет #uikit #uitextview #swift5

Вопрос:

У меня есть простая форма обратной связи, которая является одним из двух ViewControllers в TabBarController. Никаких раскадровок, полностью программный пользовательский интерфейс (UIKit), универсальное приложение. При вводе TextView на iPad консоль выдает предупреждение о макете:

     "<NSAutoresizingMaskLayoutConstraint:0x2808aa5d0 h=--amp; v=--amp; _UIButtonBarButton:0x129e8c6d0.height == 0   (active)>",
    "<NSLayoutConstraint:0x2808a9d60 V:|-(6)-[_UIUCBKBSelectionBackground:0x129e8d4e0]   (active, names: '|':_UIButtonBarButton:0x129e8c6d0 )>",
    "<NSLayoutConstraint:0x2808a9e00 _UIUCBKBSelectionBackground:0x129e8d4e0.bottom == _UIButtonBarButton:0x129e8c6d0.bottom - 6   (active)>"
  

Этого не происходит на iPhone. Кроме этого, форма работает нормально. Я понятия не имею, откуда это и как это решить. Любые советы приветствуются.

ОБНОВЛЕНИЕ; теперь это отображается во всех моих текстовых представлениях и текстовых полях при вводе. Проблема с IOS14.2?

Код ViewController:

 import UIKit
import MessageUI

struct MailOption {
    let url: URL!
    let titel: String
}

class FeedbackViewController: UIViewController, MFMailComposeViewControllerDelegate ,UINavigationControllerDelegate {
    //MARK: - Properties
    let logoImageView = ProjectImageView(frame: .zero)
    let appVersionLabel = ProjectTitleLabel(withTextAlignment: .center, andFont: UIFont.preferredFont(forTextStyle: .title3), andColor: .label, numberOfLines: 2)
    let developerLabel = ProjectTitleLabel(withTextAlignment: .center, andFont: UIFont.preferredFont(forTextStyle: .footnote), andColor: .tertiarySystemBackground, numberOfLines: 1)
    let feedbackTextView = ProjectTextView()
    let spacerView = UIView()
    let sendButton = ProjectButton(withBackgroundColor: .systemOrange, andTitle: "Send")
    
    var feedbackTextViewPlaceholder = ProjectTextViewPlaceholderTextFor.feedback
    
    let emailTo = ProjectEmailAddresses.g
    var emailBody = ""
    let emailSubject = "Feedback on (Bundle.main.displayName ?? "Unknown"), version (Bundle.main.version ?? "")"

    //MARK: - ViewController Methods
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureViewController()
        configureView()
        configureAppVersionLabel()
        configureFeedbackTextView()
        configureSendButton()
    }

    //MARK: - Actions
    @objc private func endEditing() {
        view.endEditing(true)
    }
    
    @objc func adjustForKeyboard(notification: Notification) {
        //Reset to origin position
        self.view.frame.origin.y = 0
        
        if notification.name.rawValue == "UIKeyboardWillChangeFrameNotification" {
            if feedbackTextView.isFirstResponder {
                self.view.frame.origin.y -= feedbackTextView.frame.origin.y   10
            } 
        } else {
            self.view.frame.origin.y = 0
        }
    }
    
    @objc private func sendButtonTapped() {
        //Extra check on feedback being present
        guard let feedback = feedbackTextView.text, feedback.isNotEmpty else { return }

        emailBody = feedback
        let subjectEncoded = emailSubject.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
        let bodyEncoded = emailBody.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!

        let gMail = MailOption(url: URL(string: "googlegmail://co?to=(emailTo)amp;subject=(subjectEncoded)amp;body=(bodyEncoded)"), titel: "GMail")
        let outlook = MailOption(url: URL(string: "ms-outlook://compose?to=(emailTo)amp;subject=(subjectEncoded)amp;body=(bodyEncoded)"), titel: "Outlook")
        let spark = MailOption(url: URL(string: "readdle-spark://compose?recipient=(emailTo)amp;subject=(subjectEncoded)amp;body=(bodyEncoded)"), titel: "Spark")
        
        let availableUrls = [gMail, outlook, spark].filter { (mailOption) -> Bool in
            return mailOption.url != nil amp;amp; UIApplication.shared.canOpenURL(mailOption.url)
        }

        showEmailOptions(for: availableUrls)
    }

    //MARK: - Mail functionality
    func showEmailOptions(for mailOptions: [MailOption]) {
        //Create action sheet
        let ac = UIAlertController(title: "Choose your preferred method of sending mail", message: nil, preferredStyle: .actionSheet)
        
        //Add Apple Mail action if that is available
        if MFMailComposeViewController.canSendMail() {
            ac.addAction(UIAlertAction(title: "Apple Mail", style: .default, handler: { (_) in
                self.sendAppleMail()
            }))
        }
        
        //Add other available actions
        for option in mailOptions {
            ac.addAction(UIAlertAction(title: option.titel, style: .default, handler: { (_) in
                UIApplication.shared.open(option.url, options: [:], completionHandler: { _ in
                    self.showSuccess()
                })
            }))
        }
        
        //Cancel action
        ac.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        
        //Needed for iPads
        if UIDevice.current.userInterfaceIdiom == .pad {
            ac.popoverPresentationController?.sourceView = sendButton
            ac.popoverPresentationController?.permittedArrowDirections = [.down, .up]
        }
        
        present(ac, animated: true)
    }
    
    func sendAppleMail() {
        //we already checked for availability of the Mail App!
        let composer = MFMailComposeViewController()
        
        composer.mailComposeDelegate = self
        composer.setToRecipients([emailTo])
        composer.setSubject(emailSubject)
        composer.setMessageBody(emailBody, isHTML: false)
        
        present(composer, animated: true)
    }
    
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        if result == .sent {
            self.showSuccess()
        }
        
        controller.dismiss(animated: true)
    }
    
    private func showSuccess() {
        self.presentProjectAlertOnMainThread(withTitle: "Feedback sent!", andMessage: "Thank you for your input!", andDismissButtonTitle: "OK", andConfirmButtonTitle: nil, completion: { _ in
            self.feedbackTextView.text = ""
            self.sendButton.isEnabled = false
        })
    }
    
    //MARK: - UI amp; Layout
    private func configureViewController() {
        feedbackTextView.delegate = self
        
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(endEditing)))
        
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }
    
    private func configureView() {
        let padding: CGFloat = 20
        
        logoImageView.layer.cornerRadius = 5
        logoImageView.contentMode = .scaleAspectFit

        appVersionLabel.setContentHuggingPriority(.required, for: .vertical)
        developerLabel.setContentHuggingPriority(.required, for: .vertical)
        
        spacerView.translatesAutoresizingMaskIntoConstraints = false
        
        let seperator = Separator(frame: .zero)
        
        let stackView = UIStackView(arrangedSubviews: [logoImageView, appVersionLabel, developerLabel, seperator, feedbackTextView, spacerView, sendButton])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.alignment = .center
        stackView.spacing = 10
        stackView.distribution = .fill
        
        view.addSubview(stackView)
        
        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: padding),
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -padding),
            
            logoImageView.heightAnchor.constraint(equalToConstant: 88),
            logoImageView.widthAnchor.constraint(equalTo: logoImageView.heightAnchor),
            logoImageView.centerXAnchor.constraint(equalTo: stackView.centerXAnchor),
            
            seperator.leadingAnchor.constraint(equalTo: stackView.leadingAnchor, constant: padding),
            seperator.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: -padding),
            
            feedbackTextView.widthAnchor.constraint(equalTo: stackView.widthAnchor, constant: -(2 * padding)),
            feedbackTextView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.33),
            
            spacerView.heightAnchor.constraint(greaterThanOrEqualToConstant: 22),
            spacerView.widthAnchor.constraint(equalTo: stackView.widthAnchor),
            
            sendButton.widthAnchor.constraint(equalTo: stackView.widthAnchor, constant: -(2 * padding)),
            sendButton.heightAnchor.constraint(equalToConstant: 44)
        ])

    }
    
    private func configureAppVersionLabel() {
        guard let appName = Bundle.main.displayName, let appVersion = Bundle.main.version else {
            appVersionLabel.text = "Unknown"
            return
        }
        appVersionLabel.text = "(appName)n(appVersion)"
        
        developerLabel.text = "developer"
    }
    
    @objc private func configureFeedbackTextView() {
        feedbackTextView.text = feedbackTextViewPlaceholder
        feedbackTextView.textColor = feedbackTextView.text == ProjectTextViewPlaceholderTextFor.feedback ? .tertiaryLabel : .label
    }
    
    private func configureSendButton() {
        sendButton.addTarget(self, action: #selector(sendButtonTapped), for: .touchUpInside)
        sendButton.isEnabled = false
    }
}

//MARK: - Delegate UITextView
extension FeedbackViewController: UITextViewDelegate {
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        //2000 chars restriction
        return textView.text.count   (text.count - range.length) <= 2000
    }
    
    func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.textColor == UIColor.tertiaryLabel {
            textView.text = ""
            textView.textColor = .label
        }
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.isEmpty {
            textView.text = ProjectTextViewPlaceholderTextFor.feedback
            textView.textColor = .tertiaryLabel
            feedbackTextViewPlaceholder = ""
        } else {
            feedbackTextViewPlaceholder = textView.text
        }
    }
    
    func textViewDidChange(_ textView: UITextView) {
        feedbackTextViewPlaceholder = textView.text
        
        if let text = textView.text, text.isNotEmpty, text != ProjectTextViewPlaceholderTextFor.feedback {
            sendButton.isEnabled = true
        } else {
            sendButton.isEnabled = false
        }
    }
}
  

Комментарии:

1. Вы нашли решение?

2. К сожалению, нет. Эта ошибка теперь отображается во всех текстовых полях, текстовых представлениях и панелях поиска в моем приложении. Но только на iPad…