#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…