Having issues with activating constraints programmatically and getting errors - ios

Last night I posted a question on here where I used storyboards to set the constraints. I decided to test it with anchors and do constraints programmatically.
I am getting this error:
Terminating app due to uncaught exception 'NSGenericException',
reason: 'Unable to activate constraint with anchors
and
because they have no common ancestor. Does the constraint or its
anchors reference items in different view hierarchies? That's
illegal.'
I know this has to do with views not being a subview of a certain other view however, I have checked it plenty of times and I don't know what to do.
here is the code:
import UIKit
import CoreData
class editViewController: UIViewController {
let screenSize: CGRect = UIScreen.main.bounds
let moContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var editnotes: addednotes?
let mainbackgroundview: UIView =
{
let view = UIView()
view.backgroundColor = .black
view.alpha = 0.3
return view
}()
let backgroundview1: UIView =
{
let view = UIView()
view.backgroundColor = .purple
return view
}()
let edittasktextview1: UITextView = {
let tv = UITextView()
tv.backgroundColor = .black
return tv
}()
let cancelButton : UIButton = {
let button = UIButton(type: .system)
button.setTitle("Cancel", for: .normal)
button.addTarget(self, action: #selector(handleCancelButton), for:
.touchUpInside)
return button
}()
let doneButton1 : UIButton = {
let button = UIButton(type: .system)
button.setTitle("Done", for: .normal)
button.addTarget(self, action: #selector(handleDoneButton), for: .touchUpInside)
return button
}()
#objc func handleCancelButton() {
edittasktextview1.endEditing(true)
dismiss(animated: true, completion: nil)
}
#objc func handleDoneButton()
{
dismiss(animated: true, completion: nil)
if edittasktextview1.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittasktextview1.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
edittasktextview1.endEditing(true)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NotificationID"), object: nil)
}
override func viewDidAppear(_ animated: Bool) {
//add something here
// edittasktextview.becomeFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.tintColor = UIColor.white
navigationItem.title = "Edit Tasks"
edittasktextview1.text = editnotes?.sNote
backgroundview1.backgroundColor = editnotes?.sPriorityColor
edittasktextview1.backgroundColor = .clear
setupviews()
//adding gesture to the background view to dismiss keyboard
let dismisskeyboardgesture = UITapGestureRecognizer()
dismisskeyboardgesture.addTarget(self, action: #selector(dismisskeyboard))
let maskPath = UIBezierPath.init(roundedRect: self.backgroundview1.bounds, byRoundingCorners:[.topLeft, .topRight], cornerRadii: CGSize.init(width: 20.0, height: 0))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.backgroundview1.bounds
maskLayer.path = maskPath.cgPath
self.backgroundview1.layer.mask = maskLayer
view.backgroundColor = .clear
//view.addGestureRecognizer(dismisskeyboardgesture)
view.addSubview(mainbackgroundview)
mainbackgroundview.addSubview(backgroundview1)
// view.addSubview(backgroundview1)
backgroundview1.addSubview(edittasktextview1)
backgroundview1.addSubview(cancelButton)
backgroundview1.addSubview(doneButton1)
}
#objc func dismisskeyboard()
{
edittasktextview1.endEditing(true)
}
func setupviews()
{
mainbackgroundview.anchorToTop(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
backgroundview1.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 45, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
edittasktextview1.anchor(view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 40, leftConstant: 8, bottomConstant: 0, rightConstant: 8, widthConstant: 0, heightConstant: 150)
cancelButton.anchor(edittasktextview1.bottomAnchor, left: nil, bottom: nil, right: view.rightAnchor, topConstant: 18, leftConstant: 0, bottomConstant: 0, rightConstant: 8, widthConstant: 40, heightConstant: 30)
doneButton1.anchor(edittasktextview1.bottomAnchor, left: view.leftAnchor, bottom: nil, right: nil, topConstant: 18, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 40, heightConstant: 30)
}
}
Help will be appreciated, as I am stuck at this problem for nearly 18 hours :(
UPDATE #1
Not getting the same error now, however, I am not able to set the backgroundview1 on the mainbackgroundview.
I am adding it as a subview:
mainbackgroundview.addSubview(backgroundview1)
In setupviews() I am placing the constraint like so:
NSLayoutConstraint.activate([
backgroundview1.leftAnchor.constraint(equalTo: mainbackgroundview.leftAnchor, constant: 0),
backgroundview1.rightAnchor.constraint(equalTo: mainbackgroundview.rightAnchor, constant: 0),
backgroundview1.bottomAnchor.constraint(equalTo: mainbackgroundview.bottomAnchor, constant: 0),
backgroundview1.topAnchor.constraint(equalTo: mainbackgroundview.topAnchor, constant: 45)
])
Still I am not getting the backgroundview1 to be placed on the mainbackgroundview. The mainbackgroundview is showing up though on the simulator.
I am adding mainbackgroundview like so:
NSLayoutConstraint.activate([
mainbackgroundview.leftAnchor.constraint(equalTo: view.leftAnchor),
mainbackgroundview.rightAnchor.constraint(equalTo: view.rightAnchor),
mainbackgroundview.topAnchor.constraint(equalTo: view.topAnchor),
mainbackgroundview.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
What am I doing wrong now?

In setupViews() function you are adding constraints but not setting them as active. This is a sample anchor constraint that can be added successfully:
myView.bottomAnchor.constraint(equalTo: view.topAnchor,
constant: 8).isActive=true
Try adding .isActive at the end of each of your constraint.
Moreover you can add relevant anchor constraints for example: topAnchor, bottomAnchor, widthAnchor, heightAnchor, leadingAnchor etc. Try simplifying your constraints.

Related

UIButton Not Responding to Touch Events

Problem
I am trying to do everything programmatically, so I have created this ResultController. For some reason, two of my buttons work but the other three don't work. The program doesn't even notice the touch-up event. I have read many posts on this topic but none of the solutions worked for me.
The two buttons that work are the language button and the swap button, which are embedded in a stack view towards the top of the screen. The 3 buttons that don't work are the soundButton, loopButton, and addFlashcardButton on the result card shown in the image below.
Question
What do I need to do such that these buttons respond to touch events?
Here is the code for this viewController, as well as a picture of the result. I will post the important parts and the whole code for reference. The Buttons are laid out in two functions, setupResultsView() and setupScrollView():
Button Instantiation
var soundButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "speaker.3.fill"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(soundButtonPressed), for: .touchUpInside)
return button
}()
var loopButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "repeat"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(loopButtonPressed), for: .touchUpInside)
return button
}()
var addFlashcardButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setImage(UIImage(systemName: "plus"), for: .normal)
button.backgroundColor = K.Colors.purple
button.tintColor = .white
button.roundCorners(cornerRadius: 15)
button.addTarget(self, action: #selector(addFlashcardButtonPressed), for: .touchUpInside)
return button
}()
Selector Functions
#objc func soundButtonPressed() {
print("soundButton")
}
#objc func loopButtonPressed() {
print("loopButton")
}
#objc func addFlashcardButtonPressed() {
print("adding flashcard")
}
Complete Code
import UIKit
class ResultsController: UIViewController {
//MARK: - Info
let cellID = "SoundItOutCell"
//MARK: - Views
var centerTitle: UILabel = {
let label = UILabel(frame: CGRect(x: 10, y: 0, width: 50, height: 40))
label.backgroundColor = K.Colors.purple
label.font = UIFont.boldSystemFont(ofSize: 30)
label.text = "Aura"
label.numberOfLines = 2
label.textColor = .white
label.textAlignment = .center
return label
}()
var languageBarView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.setUnderlineStyle(color: K.Colors.purple)
return view
}()
var langStackView: UIStackView = {
let stackView = UIStackView()
stackView.backgroundColor = .white
stackView.alignment = .center
stackView.distribution = .fillEqually
return stackView
}()
var languageButton: UIButton = {
let button = UIButton()
button.setTitle("Japanese", for: .normal)
button.addTarget(self, action: #selector(languageButtonPressed), for: .touchUpInside)
button.backgroundColor = .white
button.setTitleColor(UIColor.systemBlue, for: .normal)
return button
}()
var swapButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "repeat"), for: .normal)
button.addTarget(self, action: #selector(swapButtonPressed), for: .touchUpInside)
button.tintColor = .black
button.backgroundColor = .white
return button
}()
var englishLabel: UILabel = {
let label = UILabel()
label.text = "English"
label.textColor = .black
label.backgroundColor = .white
label.textAlignment = .center
return label
}()
var textViewBackgroundView = UIView()
var textView: UITextView = {
let textView = UITextView()
textView.returnKeyType = .search
textView.text = "Enter text"
textView.textColor = .lightGray
textView.font = .systemFont(ofSize: 20)
textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 50)
return textView
}()
var cancelButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "multiply"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(cancelButtonPressed), for: .touchUpInside)
button.isHidden = true
return button
}()
var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.backgroundColor = K.Colors.lightGrey
return scrollView
}()
var contentView: UIView = {
let view = UIView()
view.backgroundColor = K.Colors.lightGrey
return view
}()
var resultCardView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.roundCorners(cornerRadius: 10)
return view
}()
var topLabel = UILabel()
var bottomLabel = UILabel()
var soundButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "speaker.3.fill"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(soundButtonPressed), for: .touchUpInside)
return button
}()
var loopButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "repeat"), for: .normal)
button.backgroundColor = .white
button.tintColor = .black
button.addTarget(self, action: #selector(loopButtonPressed), for: .touchUpInside)
return button
}()
var lineDividerView: UIView = {
let view = UIView()
view.backgroundColor = K.Colors.purple
return view
}()
var addFlashcardButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setImage(UIImage(systemName: "plus"), for: .normal)
button.backgroundColor = K.Colors.purple
button.tintColor = .white
button.roundCorners(cornerRadius: 15)
button.addTarget(self, action: #selector(addFlashcardButtonPressed), for: .touchUpInside)
return button
}()
// Background Views
let resultBackgroundView = UIView ()
let addFlashcardBackgroundView = UIView()
//MARK: - Class Functions
override func viewDidLoad() {
super.viewDidLoad()
setupView()
view.backgroundColor = K.Colors.lightGrey
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setupShadows()
}
}
extension ResultsController {
//MARK:- View Setup Functions
func setupView() {
self.setupToHideKeyboardOnTapOnView()
setupNavBar()
setupLanguageSelectionView()
setupTextView()
setupScrollView()
}
func setupShadows() {
textViewBackgroundView.setShadow(color: UIColor.black, opacity: 0.3, offset: .init(width: 0, height: 3), radius: 2)
resultBackgroundView.setShadow(color: .black, opacity: 0.3, offset: CGSize(width: 5, height: 5), radius: 2, cornerRadius: 10)
addFlashcardBackgroundView.setShadow(color: .black, opacity: 0.5, offset: CGSize(width: 2, height: 2), radius: 2, cornerRadius: 15)
}
func setupNavBar() {
// Add Center Title
self.navigationItem.titleView = centerTitle
// Add userbutton
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "person"),
style: .plain,
target: self,
action: #selector(profileButtonTapped))
// Make bar color purple, and buttons white
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.barTintColor = K.Colors.purple
}
func setupLanguageSelectionView() {
// Add Language Bar View
view.addSubview(languageBarView)
languageBarView.anchor(top: view.safeAreaLayoutGuide.topAnchor,
bottom: nil, leading: view.leadingAnchor,
trailing: view.trailingAnchor,
height: 60,
width: nil)
// Add Stack View
languageBarView.addSubview(langStackView)
langStackView.anchor(top: languageBarView.topAnchor,
bottom: languageBarView.bottomAnchor,
leading: languageBarView.leadingAnchor,
trailing: languageBarView.trailingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 0, left: 0, bottom: -2, right: 0))
// Add Language Button
langStackView.addArrangedSubview(languageButton)
// Add Swap Button
langStackView.addArrangedSubview(swapButton)
// Add English Label
langStackView.addArrangedSubview(englishLabel)
}
func setupTextView() {
// Add View
view.addSubview(textViewBackgroundView)
textViewBackgroundView.anchor(top: langStackView.bottomAnchor,
bottom: nil,
leading: view.leadingAnchor,
trailing: view.trailingAnchor,
height: 60,
width: nil,
padding: UIEdgeInsets(top: 2, left: 0, bottom: 0, right: 0))
// Add TextView
textView.delegate = self
view.addSubview(textView)
textView.anchor(top: textViewBackgroundView.topAnchor,
bottom: textViewBackgroundView.bottomAnchor,
leading: textViewBackgroundView.leadingAnchor,
trailing: textViewBackgroundView.trailingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
// Add X Button
view.addSubview(cancelButton)
cancelButton.anchor(top: textView.topAnchor,
bottom: nil,
leading: nil,
trailing: textView.trailingAnchor,
height: 40,
width: 40,
padding: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
}
func setupScrollView() {
// Add scroll view and content view
view.addSubview(scrollView)
view.sendSubviewToBack(scrollView)
scrollView.addSubview(contentView)
// Anchor Scroll View
scrollView.anchorXCenter(top: textView.topAnchor,
bottom: view.safeAreaLayoutGuide.bottomAnchor,
centerAnchor: view.centerXAnchor,
width: view.widthAnchor,
height: nil)
// Anchor Content View
contentView.anchorXCenter(top: scrollView.topAnchor,
bottom: scrollView.bottomAnchor,
centerAnchor: scrollView.centerXAnchor,
width: scrollView.widthAnchor,
height: nil)
// Setup Results Background
contentView.addSubview(resultBackgroundView)
resultBackgroundView.anchorXCenter(top: contentView.topAnchor,
bottom: nil,
centerAnchor: contentView.centerXAnchor,
width: contentView.widthAnchor,
height: nil,
padding: UIEdgeInsets(top: 90, left: 0, bottom: 0, right: 0),
widthOffset: -40)
// Setup Results Card
resultBackgroundView.addSubview(resultCardView)
resultCardView.anchorXCenter(top: resultBackgroundView.topAnchor,
bottom: resultBackgroundView.bottomAnchor,
centerAnchor: resultBackgroundView.centerXAnchor,
width: resultBackgroundView.widthAnchor,
height: nil)
setupResultsView(resultCardView)
}
func setupResultsView(_ resultCardView: UIView) {
let searchInput = "Hello"
let searchOutput = "Yo what's up dog congratulations"
// Configure Top Label
topLabel.attributedText = NSAttributedString(string: searchInput)
topLabel.configureBasedOnInput()
// Configure Bottom Label
bottomLabel.attributedText = NSAttributedString(string: searchOutput)
bottomLabel.configureBasedOnInput()
// Add Flashcard Button to its Background View
addFlashcardBackgroundView.addSubview(addFlashcardButton)
addFlashcardButton.anchor(top: addFlashcardBackgroundView.topAnchor,
bottom: addFlashcardBackgroundView.bottomAnchor,
leading: addFlashcardBackgroundView.leadingAnchor,
trailing: addFlashcardBackgroundView.trailingAnchor,
height: nil,
width: nil)
// Add subviews to Result Card
resultCardView.addSubview(topLabel)
resultCardView.addSubview(bottomLabel)
resultCardView.addSubview(soundButton)
resultCardView.addSubview(loopButton)
resultCardView.addSubview(lineDividerView)
resultCardView.addSubview(addFlashcardBackgroundView)
// Autolayout Constraints For Result Card Subviews
topLabel.translatesAutoresizingMaskIntoConstraints = false
topLabel.topAnchor.constraint(equalTo: resultCardView.topAnchor, constant: 10).isActive = true
topLabel.centerXAnchor.constraint(equalTo: resultCardView.centerXAnchor, constant: 0).isActive = true
topLabel.leadingAnchor.constraint(greaterThanOrEqualTo: resultCardView.leadingAnchor, constant: 10).isActive = true
topLabel.trailingAnchor.constraint(lessThanOrEqualTo: resultCardView.trailingAnchor, constant: -10).isActive = true
lineDividerView.anchor(top: topLabel.bottomAnchor,
bottom: nil, leading: resultCardView.leadingAnchor,
trailing: resultCardView.trailingAnchor,
height: 1,
width: nil,
padding: UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0))
loopButton.anchor(top: lineDividerView.bottomAnchor,
bottom: nil,
leading: nil,
trailing: resultCardView.trailingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 10, left: 0, bottom: 0, right: -10))
soundButton.anchor(top: lineDividerView.bottomAnchor,
bottom: nil,
leading: nil,
trailing: loopButton.leadingAnchor,
height: nil,
width: nil,
padding: UIEdgeInsets(top: 10, left: 0, bottom: 0, right: -10))
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
bottomLabel.topAnchor.constraint(equalTo: soundButton.bottomAnchor, constant: 10).isActive = true
bottomLabel.centerXAnchor.constraint(equalTo: resultCardView.centerXAnchor, constant: 0).isActive = true
bottomLabel.leadingAnchor.constraint(greaterThanOrEqualTo: resultCardView.leadingAnchor, constant: 10).isActive = true
bottomLabel.trailingAnchor.constraint(lessThanOrEqualTo: resultCardView.trailingAnchor, constant: -10).isActive = true
addFlashcardBackgroundView.anchor(top: bottomLabel.bottomAnchor,
bottom: resultCardView.bottomAnchor,
leading: nil,
trailing: resultCardView.trailingAnchor,
height: 30,
width: 30,
padding: UIEdgeInsets(top: 10, left: 0, bottom: -10, right: -10))
}
//MARK:- Selector Functions
#objc func profileButtonTapped() {
print(0)
}
#objc func languageButtonPressed() {
print(1)
}
#objc func swapButtonPressed() {
print(2)
}
#objc func cancelButtonPressed() {
textView.text = ""
textView.textColor = .lightGray
textView.text = "Enter text"
cancelButton.isHidden = true
}
#objc func soundButtonPressed() {
print("soundButton")
}
#objc func loopButtonPressed() {
print("loopButton")
}
#objc func addFlashcardButtonPressed() {
print("adding flashcard")
}
}
Output: Circled Buttons are ones that don't work

How to segue smoothly from UITableViewController to UIViewController programmatically

I'm not using storyboard and I'm doing everything programmatically.
So my problem is that when try to run the app on my phone (This does not happen when I use the simulator in Xcode), and when I use the following method...
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let destinationVC = ThirdViewController()
destinationVC.selectedExercise = exercises![indexPath.row]
self.navigationController?.pushViewController(destinationVC, animated: true)
}
...to transition from a UITableView to a UIView, the contents of the View transition normally, but the background freezes for a second before transitioning to the UIView.
What's causing this and how can I fix this?
Here is the code for the viewController that I'm transitioning to.
import UIKit
import RealmSwift
class ThirdViewController: UIViewController, UITextViewDelegate {
let realm = try! Realm()
var stats : Results<WeightSetsReps>?
var weightTextField = UITextField()
var weightLabel = UILabel()
var notesTextView = UITextView()
var repsTextField = UITextField()
var repsLabel = UILabel()
var timerImage = UIImageView()
var nextSet = UIButton()
var nextExcersise = UIButton()
var selectedExercise : Exercises? {
didSet{
loadWsr()
}
}
//MARK: - ViewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
notesTextView.delegate = self
timeClock()
navConAcc()
labelConfig()
setTextFieldConstraints()
setImageViewConstraints()
setTextViewConstraints()
setButtonConstraints()
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
//MARK: - UILabel
func labelConfig(){
weightTextField.placeholder = "Total weight..."
weightTextField.layer.borderWidth = 1
weightTextField.backgroundColor = .white
weightTextField.layer.cornerRadius = 25
weightTextField.layer.borderColor = UIColor.lightGray.cgColor
weightLabel.text = " Weight (lbs): "
weightLabel.textColor = .black
weightTextField.leftView = weightLabel
weightTextField.leftViewMode = .always
repsTextField.placeholder = "Number of Reps..."
repsTextField.layer.borderWidth = 1
repsTextField.backgroundColor = .white
repsTextField.layer.cornerRadius = 25
repsTextField.layer.borderColor = UIColor.lightGray.cgColor
repsLabel.text = " Repetitions: "
repsLabel.textColor = .black
notesTextView.layer.borderWidth = 1
notesTextView.backgroundColor = .white
notesTextView.layer.cornerRadius = 25
notesTextView.layer.borderColor = UIColor.lightGray.cgColor
notesTextView.text = " Notes..."
notesTextView.textColor = UIColor.lightGray
notesTextView.returnKeyType = .done
repsTextField.leftView = repsLabel
repsTextField.leftViewMode = .always
nextSet.layer.borderWidth = 1
nextSet.backgroundColor = .white
nextSet.layer.cornerRadius = 25
nextSet.layer.borderColor = UIColor.lightGray.cgColor
nextSet.setTitle("Next Set", for: .normal)
nextSet.setTitleColor(.black, for: .normal)
nextSet.addTarget(self, action: #selector(addNewSet), for: .touchUpInside)
nextExcersise.layer.borderWidth = 1
nextExcersise.backgroundColor = .white
nextExcersise.layer.cornerRadius = 25
nextExcersise.layer.borderColor = UIColor.lightGray.cgColor
nextExcersise.setTitle("Next Exercise", for: .normal)
nextExcersise.setTitleColor(.black, for: .normal)
[weightTextField, repsTextField, notesTextView, nextSet, nextExcersise].forEach{view.addSubview($0)}
}
//MARK: - TextView Delegates
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.text == " Notes..." {
textView.text = ""
textView.textColor = UIColor.black
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == "\n" {
textView.resignFirstResponder()
}
return true
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text == ""{
notesTextView.text = " Notes..."
notesTextView.layer.borderColor = UIColor.lightGray.cgColor
}
}
//MARK: - Dismiss Keyboard Function
#objc func dismissKeyboard(){
view.endEditing(true)
}
//MARK: - TextField Constraints
func setTextFieldConstraints(){
weightTextField.anchor(top: view.safeAreaLayoutGuide.topAnchor, leading: view.leadingAnchor, bottom: nil, trailing: view.trailingAnchor,padding: .init(top: 20, left: 40, bottom: 0, right: -40), size: .init(width: 0, height: 50))
repsTextField.anchor(top: weightTextField.bottomAnchor, leading: view.leadingAnchor, bottom: nil, trailing: view.trailingAnchor, padding: .init(top: 30, left: 40, bottom: 0, right: -40) ,size: .init(width: 0, height: 50))
}
//MARK: - UIButton Functions
#objc func addNewSet(){
print("It Works")
}
//MARK: - UIButton Constraints
func setButtonConstraints(){
nextSet.anchor(top: nil, leading: view.leadingAnchor, bottom: view.safeAreaLayoutGuide.bottomAnchor, trailing: nil, padding: .init(top: 0, left: 40, bottom: 0, right: -150), size: .init(width: 120, height: 70))
nextExcersise.anchor(top: nil, leading: nextSet.trailingAnchor, bottom: nextSet.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 85, bottom: 0, right: -40), size: .init(width: 120, height: 70))
}
//MARK: - ImageView Constraints
func setImageViewConstraints(){
timerImage.anchor(top: repsTextField.bottomAnchor, leading: view.leadingAnchor, bottom: nil, trailing: view.trailingAnchor, padding: .init(top: 40, left: 0, bottom: 0, right: 0), size: .init(width: 100, height: 100))
}
//MARK: - TextView Constraints
func setTextViewConstraints(){
notesTextView.anchor(top: timerImage.bottomAnchor, leading: view.leadingAnchor, bottom: nil, trailing: view.trailingAnchor, padding: .init(top: 40, left: 40, bottom: 0, right: -40), size: .init(width: 100, height: 110))
}
//MARK: - Navigation Bar Setup
func navConAcc(){
navigationItem.title = selectedExercise?.exerciseName
navigationController?.navigationBar.prefersLargeTitles = true
}
//MARK: - Stopwatch
func timeClock(){
let image1 = UIImage(named: "stopwatch")
timerImage = UIImageView(image: image1)
timerImage.contentMode = .scaleAspectFit
self.view.addSubview(timerImage)
}
//MARK: - Load Data
func loadWsr() {
stats = selectedExercise?.wsr.sorted(byKeyPath: "sets", ascending: true)
}
//MARK: - Save Data
func save(wsr : WeightSetsReps){
do {
try realm.write {
realm.add(wsr)
}
} catch {
print("Error saving wsr data \(error)")
}
}
}
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero){
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: padding.bottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: padding.right).isActive = true
}
if size.width != 0 {
widthAnchor.constraint(equalToConstant: size.width).isActive = true
}
if size.height != 0 {
heightAnchor.constraint(equalToConstant: size.height).isActive = true
}
}
}
You're not implementing programmatic view controllers correctly. A programmatically-created view controller does all of its view building in loadView(), not viewDidLoad(). Therefore, add all of the view controller's subviews in loadView() (without calling super.loadView()). Then use viewDidLoad() (with calling super.viewDidLoad()) to do post-view work, like adding timers, notification observers, etc. I suspect the lagging is caused by an incorrectly-configured lifecycle.
It also appears you're relatively new to iOS or Swift development and so I would strongly suggest you do not use extensions, especially on UIView for auto layout. Learn how it all works first before you begin extending things. The process for programmatic auto layout is:
// adjust parameters first, like color, delegate, etc.
someView.translatesAutoresizingMaskIntoConstraints = false // set resizing to false before adding as a subview
view.addSubview(someView) // add as a subview
someView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true // add constraints

Unable to activate constraint with anchors while adding a textfield

A while ago I started creating my screens via the storyboard.
Recently I have been convinced doing it programmatically.
Currently I am running into the following error:
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors and because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'
import UIKit
class ViewController: UIViewController {
var emailTextField: UITextField {
let tf = UITextField()
tf.placeholder = "email";
tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
tf.borderStyle = .roundedRect
tf.font = UIFont.systemFont(ofSize: 14)
return tf
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(emailTextField)
emailTextField.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 40, paddingLeft: 20, paddingBottom: 0, paddingRight: 20, width: 0, height: 40)
}
}
I have created a function to anchor my elements in Extensions.swift:
import UIKit
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, left: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, right: NSLayoutXAxisAnchor?, paddingTop: CGFloat, paddingLeft: CGFloat, paddingBottom: CGFloat, paddingRight: CGFloat, width: CGFloat, height: CGFloat) {
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
self.topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let left = left {
self.leftAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
}
if let bottom = bottom {
self.bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
}
if let right = right {
self.rightAnchor.constraint(equalTo: right, constant: -paddingRight).isActive = true
}
if width != 0 {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if height != 0 {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
}
In addition, I deleted the Application Scene Manifest in Info.plist.
I want my project to support the upcoming iOS versions starting at 13.0.
Nevertheless I don't want to use the new framework SwiftUI.
Are there any specific things to watch out for (e.g. Scene Delegate)?
Thank you in advance!
You need to change this
var emailTextField: UITextField {
let tf = UITextField()
tf.placeholder = "email";
tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
tf.borderStyle = .roundedRect
tf.font = UIFont.systemFont(ofSize: 14)
return tf
}
into this
var emailTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "email";
tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
tf.borderStyle = .roundedRect
tf.font = UIFont.systemFont(ofSize: 14)
return tf
}()
In current version emailTextField is computed property, so, every time you access it compiler create a new instance (it works like function, not variable).
Textfield was unable to get its parent view while you were adding its constraint. Below code works for me. I passed current view as a param to anchor() method and add emailTextField as a subview there.
class ViewController: UIViewController {
var emailTextField:UITextField = {
let tf = UITextField()
tf.placeholder = "email";
tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
tf.borderStyle = .roundedRect
tf.font = UIFont.systemFont(ofSize: 14)
return tf
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
emailTextField.anchor(top: view.safeAreaLayoutGuide.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 40, paddingLeft: 20, paddingBottom: 0, paddingRight: 20, width: 0, height: 40, view:view)
}
}
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, left: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, right: NSLayoutXAxisAnchor?, paddingTop: CGFloat, paddingLeft: CGFloat, paddingBottom: CGFloat, paddingRight: CGFloat, width: CGFloat, height: CGFloat, view:UIView) {
translatesAutoresizingMaskIntoConstraints = false
view.addSubview(self)
if let top = top {
self.topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let left = left {
self.leftAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
}
if let bottom = bottom {
self.bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
}
if let right = right {
self.rightAnchor.constraint(equalTo: right, constant: -paddingRight).isActive = true
}
if width != 0 {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if height != 0 {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
}

Tableviews delegate eats button click

I got a large UITableViewCell representing a place. Elements of the cell are two Buttons starButton and infoButton. Both of them have a targetAction which never gets executed and I'm clueless why.. All touches are being eaten by the didSelectRowAt by the tableview. The thing that gets me so confused is the fact that It all worked well some hours ago and I did not change properties of the two buttons. Does someone has an idea what's going on?
The Hierarchy looks like this:
UITableView
OverviewTableCell UITableViewCell
dotsButton, thumbnailImageView UIButton , UIImageView
blackView UIView
titleLabel, descriptionLabel, starButton, infoButton UILabel , UIButton
Cell:
class OverviewTableViewCell: UITableViewCell, ReusableView {
lazy var dotsButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(named: GSSettings.UI.otherIcons.dotsHorizontal)?.withRenderingMode(.alwaysTemplate), for: .normal)
button.setImage(UIImage(named: GSSettings.UI.otherIcons.dotsVertical)?.withRenderingMode(.alwaysTemplate), for: .selected)
button.addTarget(self, action: #selector(seeMore), for: .touchUpInside)
button.fixHeightAndWidth(width: 28, height: 28)
button.tintColor = UIColor.gray
return button
}()
let thumbnailImageView: UIImageView = {
let imageview = UIImageView()
imageview.contentMode = .scaleAspectFill
imageview.clipsToBounds = true
imageview.image = UIImage(named: "testbild")
return imageview
}()
let blackView: UIImageView = {
let imageview = UIImageView()
imageview.backgroundColor = UIColor.black.withAlphaComponent(0.35)
return imageview
}()
let titleLabel : UILabel = {
let label = UILabel()
label.text = "Titel Titel"
label.font = GSSettings.UI.Fonts.helveticaMedium?.withSize(22)
label.textColor = UIColor.white
return label
}()
lazy var starButton: GSFavSpotButton = {
let button = GSFavSpotButton()
button.tintColor = UIColor.white//GSSettings.UI.Colors.nightOrange
button.addTarget(self, action: #selector(handleStarButton), for: .touchUpInside)
return button
}()
lazy var infoButton: GSInfoButton = {
let button = GSInfoButton()
button.tintColor = UIColor.white//GSSettings.UI.Colors.nightOrange
button.addTarget(self, action: #selector(handleInfoButton), for: .touchUpInside)
return button
}()
let addFriendView = GSInviteAFriendView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.clipsToBounds = false
self.selectionStyle = .none
setupSubviews()
setupConstraints()
perform(#selector(printBounds), with: nil, afterDelay: 5)
}
func setupSubviews() {
self.addSubview(dotsButton)
self.addSubview(thumbnailImageView)
thumbnailImageView.addSubview(blackView)
blackView.addSubview(titleLabel)
blackView.addSubview(descriptionLabel)
blackView.addSubview(starButton)
blackView.addSubview(infoButton)
self.addSubview(addFriendView)
blackView.isHidden = true
descriptionLabel.isHidden = true
}
func setupConstraints() {
dotsButton.anchor(top: topAnchor, leading: nil, bottom: nil, trailing: trailingAnchor, paddingTop: 0, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 16, width: 0, height: 0)
thumbnailImageView.anchor(top: dotsButton.bottomAnchor, leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, paddingTop: 4, paddingLeading: 16, paddingBottom: 0, paddingTrailing: 16, width: 0, height: 0)
thumbnailImageView.heightAnchor.constraint(equalTo: thumbnailImageView.widthAnchor, multiplier: 9/16).isActive = true
blackView.fillSuperview(unsafeArea: true)
titleLabel.anchor(top: thumbnailImageView.topAnchor, leading: thumbnailImageView.leadingAnchor, bottom: nil, trailing: starButton.leadingAnchor, paddingTop: 8, paddingLeading: 8, paddingBottom: 0, paddingTrailing: 8, width: 0, height: 20)
infoButton.anchor(top: thumbnailImageView.topAnchor, leading: nil, bottom: nil, trailing: thumbnailImageView.trailingAnchor, paddingTop: 8, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 8, width: 30, height: 30)
starButton.anchor(top: thumbnailImageView.topAnchor, leading: nil, bottom: nil, trailing: infoButton.leadingAnchor, paddingTop: 8, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 4, width: 30, height: 30)
addFriendView.anchor(top: thumbnailImageView.bottomAnchor, leading: nil, bottom: nil, trailing: nil, paddingTop: -GSSettings.UI.Sizes.addFriendButtonSize/2 + 10, paddingLeading: 0, paddingBottom: 0, paddingTrailing: 0, width: GSSettings.UI.Sizes.addFriendButtonSize, height: GSSettings.UI.Sizes.addFriendButtonSize)
addFriendView.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
}
#objc func seeMore() {
dotsButton.isSelected.toggle()
if dotsButton.isSelected {
blackView.isHidden = false
} else {
blackView.isHidden = false
}
layoutIfNeeded()
}
#objc func handleStarButton() {
starButton.isSelected.toggle()
}
#objc func handleInfoButton() {
infoButton.isSelected.toggle()
}
#objc func printBounds() {
print("::::")
print(thumbnailImageView.bounds)
print(infoButton.bounds)
print(starButton.bounds)
print("_____")
print(thumbnailImageView.frame)
print(infoButton.frame)
print(starButton.frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, paddingTop: CGFloat, paddingLeading: CGFloat, paddingBottom: CGFloat, paddingTrailing: CGFloat, width: CGFloat, height: CGFloat) {
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: leading, constant: paddingLeading).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
}
if let trailing = trailing {
trailingAnchor.constraint(equalTo: trailing, constant: -paddingTrailing).isActive = true
}
if width != 0 {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if height != 0 {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
Tableview:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: OverviewTableViewCell.reuseIdentifier, for: indexPath) as! OverviewTableViewCell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
delegate?.pushTo()
}
The printBounds() function in the cell shows that the frame and bounds are okay (I guess)
(0.0, 0.0, 382.0, 215.0)
(0.0, 0.0, 30.0, 30.0)
(0.0, 0.0, 30.0, 30.0)
(16.0, 32.0, 382.0, 215.0)
(344.0, 8.0, 30.0, 30.0)
(310.0, 8.0, 30.0, 30.0)
You can try
blackView.isUserInteractionEnabled = true
also add the subviews to
self.contentView and create the constraints of cell subviews with it

Why a navigation bar button item doesn't work when the textview has been resignedFirstResponder()?

Here is an odd one. I have two bar button items, one is cancel and one is done. The done button saves the text in the textview in the coreData and then pops the current view from the navigationController and goes to previous viewcontroller. The cancel button just goes to the previous controller. The whole thing works when the textview is the firstResponder() or the keyboard is up. When the keyboard resigns as the firstResponder, both buttons don't work. As in the just don't do anything. Done button doesn't save the text nor it takes me to previous viewcontroller.
Here is the code for both the buttons:
Done button:
#objc func handleDoneButton() {
print("hello")
if edittaskview.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittaskview.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
_ = navigationController?.popViewController(animated: true)
}
Cancel button:
#objc func handleCancelButton()
{
_ = navigationController?.popViewController(animated: true)
}
Again, the code in both these functions work when the buttons are tapped only when the textview is the first responder otherwise they don't.
ViewController code:
import UIKit
import CoreData
class editViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout,
UITextViewDelegate, UIGestureRecognizerDelegate{
var editnotes: addednotes?
var prioritynumber: Int = 1
let moContext = (UIApplication.shared.delegate as!
AppDelegate).persistentContainer.viewContext
var colorArray = [prioritylevels]()
lazy var edittaskview: UITextView = {
let textview = UITextView()
textview.isScrollEnabled = false
textview.font = UIFont.systemFont(ofSize: 16)
textview.backgroundColor = .white
textview.delegate = self
return textview
}()
var clearview: UIView = {
let view = UIView()
view.backgroundColor = .clear
//view.isUserInteractionEnabled = false
return view
}()
let rightBarButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(handleDoneButton))
let leftBarButton = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(handleCancelButton))
lazy var priorityCV: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.delegate = self
cv.dataSource = self
return cv
}()
let line: UIView = {
let line = UIView()
return line
}()
let reminderView: UIView = {
let reminder = UIView()
reminder.backgroundColor = .white
return reminder
}()
let reminderTitle: UILabel = {
let title = UILabel()
title.text = "Due Date"
title.textColor = .black
title.font = UIFont(name: "Avenir Next", size: 16)
title.font = UIFont.boldSystemFont(ofSize: 16)
return title
}()
let reminderMsg: UILabel = {
let title = UILabel()
title.text = "No Due Date Set"
title.textColor = .black
// title.font = UIFont(name: "Avenir Next", size: 12)
title.font = UIFont.systemFont(ofSize: 12)
return title
}()
let reminderAddBtn: UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Set", for: .normal)
btn.setTitleColor(.black, for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 14)
btn.addTarget(self, action: #selector(handleSetReminderBtn), for: .touchUpInside)
return btn
}()
var textHeightConstraint: NSLayoutConstraint?
override func viewWillAppear(_ animated: Bool) {
adjustTextViewHeight()
}
let datePicker: UIDatePicker = UIDatePicker()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red:0.97, green:0.97, blue:0.97, alpha:1.0)
datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged)
//ColorArray for PriorityCV
colorArray = [prioritylevels(color: UIColor(red:0.00, green:0.78, blue:0.73, alpha:1.0), name: " Low", prioritynumber: 1), prioritylevels(color: UIColor(red:0.00, green:0.78, blue:0.35, alpha:1.0), name: "Medium", prioritynumber: 2),prioritylevels(color: UIColor(red:0.88, green:0.63, blue:0.00, alpha:1.0), name: " High", prioritynumber: 3), prioritylevels(color: UIColor(red:0.96, green:0.28, blue:0.70, alpha:1.0), name: "Urgent", prioritynumber: 4)]
priorityCV.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cvid")
navigationItem.title = "Edit Task"
self.navigationItem.setHidesBackButton(true, animated: false)
self.navigationController?.navigationBar.tintColor = UIColor.white
navigationItem.rightBarButtonItem = rightBarButton
navigationItem.leftBarButtonItem = leftBarButton
view.addSubview(clearview)
clearview.addSubview(line)
clearview.addSubview(edittaskview)
clearview.addSubview(priorityCV)
clearview.addSubview(reminderView)
reminderView.addSubview(reminderTitle)
reminderView.addSubview(reminderMsg)
reminderView.addSubview(reminderAddBtn)
edittaskview.text = editnotes?.sNote
edittaskview.becomeFirstResponder() //taskview becomes first responder here when the view is loaded.
// view.addSubview(datePicker)
setupViews()
line.backgroundColor = editnotes?.sPriorityColor
let dismissbytap = UITapGestureRecognizer()
dismissbytap.addTarget(self, action: #selector(handleDismissByTap))
dismissbytap.delegate = self
clearview.addGestureRecognizer(dismissbytap) //a clear uiview is added behind all the subviews. this uiview is used to dismiss keyboard when tapped on it.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colorArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cvid", for: indexPath)
cell.backgroundColor = colorArray[indexPath.row].color
let prioritylabel = UILabel(frame: CGRect(x: view.frame.width / 20, y: 0, width: view.frame.width / 4, height: 30))
cell.addSubview(prioritylabel)
prioritylabel.text = colorArray[indexPath.row].name
prioritylabel.textColor = .white
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width / 4, height: 30)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
prioritynumber = colorArray[indexPath.row].prioritynumber
line.backgroundColor = colorArray[indexPath.row].color
editnotes?.sPriorityColor = colorArray[indexPath.row].color
editnotes?.sPriorityNumber = prioritynumber
print(prioritynumber)
}
func setupViews()
{
_ = edittaskview.anchor(line.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 2, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
self.edittaskview.contentInset = UIEdgeInsetsMake(2, 8, 4, 8)
self.textHeightConstraint = edittaskview.heightAnchor.constraint(equalToConstant: 80)
self.textHeightConstraint?.isActive = true
self.adjustTextViewHeight()
_ = clearview.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
_ = priorityCV.anchor(edittaskview.bottomAnchor, left: clearview.leftAnchor, bottom: nil, right: clearview.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 30)
_ = line.anchor(clearview.topAnchor, left: clearview.leftAnchor, bottom: nil, right: clearview.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 4)
_ = reminderView.anchor(priorityCV.bottomAnchor, left: clearview.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 30, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 60)
_ = reminderTitle.anchor(reminderView.topAnchor, left: reminderView.leftAnchor, bottom: nil, right: nil, topConstant: 8, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 20)
_ = reminderMsg.anchor(reminderTitle.bottomAnchor, left: reminderView.leftAnchor, bottom: nil, right: nil, topConstant: 4, leftConstant: 8, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 24)
_ = reminderAddBtn.anchor(reminderView.topAnchor, left: nil, bottom: nil, right: reminderView.rightAnchor, topConstant: 20, leftConstant: 0, bottomConstant: 20, rightConstant: 32, widthConstant: 30, heightConstant: 20)
}
#objc func handleDoneButton() {
print("hello")
if edittaskview.text.isEmpty == true
{
moContext.delete(editnotes!)
}
else
{
editnotes?.sNote = edittaskview.text
}
var error: NSError?
do {
// Save The object
try moContext.save()
print("SAVED")
} catch let error1 as NSError {
error = error1
}
_ = navigationController?.popViewController(animated: true)
}
func textViewDidChange(_ textView: UITextView) {
self.adjustTextViewHeight()
}
func adjustTextViewHeight() {
let fixedWidth = edittaskview.frame.size.width
let newSize = edittaskview.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
self.textHeightConstraint?.constant = newSize.height + 15
self.view.layoutIfNeeded()
}
#objc func handleCancelButton()
{
_ = navigationController?.popViewController(animated: true)
}
#objc func datePickerValueChanged(_ sender: UIDatePicker) {
let componenets = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: sender.date)
if let day = componenets.day, let month = componenets.month, let year = componenets.year, let hour = componenets.hour, let minute = componenets.minute {
print("\(day) \(month) \(year) \(hour) \(minute)")
}
}
#objc func handleDismissByTap() {
edittaskview.resignFirstResponder() // Resigning textview as first responder
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
This does seem odd - and I don't know why the navigation bar buttons are only calling the functions when your text view is active, but...
One way around it is to move your right and left UIBarButtonItem declarations into viewDidLoad() instead of at the class level.
As an aside, you'll get a better animation and keyboard appearance if you move edittaskview.becomeFirstResponder() from viewDidLoad() to viewDidAppear().
I don't know how but instead of creating bar buttons seperately and then assigning them like so self.navigationBarItem.leftbarbutton = leftBarbutton
I decided to construct them using UIBarButtonItem constructor.
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .done, target: self, action: #selector(handleCancelButton))
It worked!
Pretty odd to be honest.
Something you could do as well is making the declaration of your UIBarButtonItem a lazy var.
It's getting instantiated with the class. If you make it a lazy var it will get created when you need to use it. If you want to keep it a let and at class level, just do:
override func viewDidLoad() {
super.viewDidLoad()
yourBarButtonItem.target = self
}
Either of these methods will keep the target intact. I was having this same issue.
It's still a weird issue and I think the compiler should yell at you for trying to use self before initialization. It does so when you put self() instead.

Resources