Swift UITextView invisible with contraints - ios

I am adding a UITextView to the screen and adding the constraints but it does not show up on the view.
class ViewController: UIViewController {
let balanceTitle: UITextView = {
let textView = UITextView();
textView.text = "hello balance";
textView.translatesAutoresizingMaskIntoConstraints = false;
textView.textColor = .red;
textView.backgroundColor = .gray;
return textView;
}()
let labelTitle: UILabel = {
let lblView = UILabel();
lblView.text = "mmsmsmsmsmsmsmsm";
lblView.textColor = .red;
lblView.translatesAutoresizingMaskIntoConstraints = false;
return lblView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//view.backgroundColor = .gray
//view.addSubview(balanceTitle)
view.addSubview(balanceTitle);
balanceTitle.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true;
balanceTitle.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true;
balanceTitle.heightAnchor.constraint(equalToConstant: 400).isActive = true;
}
}
Below is the results that I get after running the code.

You need to add width constraint
NSLayoutConstraint.activate([
balanceTitle.centerYAnchor.constraint(equalTo: view.centerYAnchor),
balanceTitle.centerXAnchor.constraint(equalTo: view.centerXAnchor),
balanceTitle.heightAnchor.constraint(equalToConstant: 400),
balanceTitle.widthAnchor.constraint(equalToConstant: 200)
])
Or like this for a proportional value with view
balanceTitle.widthAnchor.constraint(equalTo:view.widthAnchor, multiplier: 0.8)

Related

Add tap gesture to a nested stackview

I've been trying to add tap gesture to a list of stackviews which are deeply nested in another stackview and a scrollview.
I'm not sure why is my implementation is not working.
In my code I'm using a selector but I would like to use a closure so I could pass into a function with parameters something like this (linkToOpen:String)->Void
import UIKit
import PlaygroundSupport
class TestViewController: UIViewController {
var aboutText:[String] = []
var fbLinks:[String] = []
let scrollView = UIScrollView()
let stackView = UIStackView()
let tap = UITapGestureRecognizer(target: self, action: #selector(didTapCard(sender: )))
override func viewDidLoad() {
super.viewDidLoad()
//Add and setup scroll view
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -5).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true;
self.scrollView.addSubview(self.stackView)
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
self.stackView.alignment = UIStackView.Alignment.fill
self.stackView.spacing = 10;
//constrain stack view to scroll view
self.stackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor).isActive = true;
self.stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true;
self.stackView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor).isActive = true;
self.stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true;
self.stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true;
fbLinks.append("Some text")
fbLinks.append("Some other text but longer")
fbLinks.append("Some other text but way longer then the previous was")
fbLinks.append("text again what a surprise")
fbLinks.append("guess what this is a text too")
for link in fbLinks
{
let sw:UIStackView = generateStackedItem(imageName:"bolt",text: link)
stackView.addArrangedSubview(sw)
}
}
func generateText(text:String)->UILabel
{
let textLabel = UILabel()
textLabel.text = NSLocalizedString(text, comment: "")
textLabel.textAlignment = .left
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
return textLabel
}
func generateStackedItem(imageName:String,text:String)->UIStackView
{
let stackView = UIStackView()
stackView.axis = NSLayoutConstraint.Axis.horizontal
stackView.distribution = .fill
stackView.alignment = .center
stackView.spacing = 5.0
let label = generateText(text: text)
//stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.heightAnchor.constraint(equalTo: label.heightAnchor, constant: 5).isActive = true
stackView.isUserInteractionEnabled = true
stackView.addGestureRecognizer(tap)
return stackView
}
func openLink(link:String){
if let url = URL(string: link) {
UIApplication.shared.open(url)
}
}
#objc func didTapCard (sender: UITapGestureRecognizer) {
// let clickedView = cardView[sender.view!.tag]
print("View tapped !")
}
}
let vc = TestViewController()
vc.view.backgroundColor = .white
PlaygroundPage.current.liveView = vc
You can add a gesture recognizer to only one view.
Think of it like a label...
If you instantiate a label, then try to add it to 4 different stack views, it will only exist in the last stack view to which you've added it.
So, you need to create a new recognizer for each view:
stackView.isUserInteractionEnabled = true
// create new Tap Gesture Reconizer here
let tap = UITapGestureRecognizer(target: self, action: #selector(didTapCard(sender:)))
stackView.addGestureRecognizer(tap)
Then, in your action selector, you can get a reference to that view (and its properties / subviews / etc):
#objc func didTapCard (sender: UITapGestureRecognizer) {
if let sv = sender.view as? UIStackView,
let label = sv.arrangedSubviews.first as? UILabel,
let str = label.text {
print("Stack view with:", str, "was tapped!")
}
}
Here is your complete class, edited with those changes:
class TestViewController: UIViewController {
var aboutText:[String] = []
var fbLinks:[String] = []
let scrollView = UIScrollView()
let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
//Add and setup scroll view
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -5).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true;
self.scrollView.addSubview(self.stackView)
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
self.stackView.alignment = UIStackView.Alignment.fill
self.stackView.spacing = 10;
//constrain stack view to scroll view
self.stackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor).isActive = true;
self.stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true;
self.stackView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor).isActive = true;
self.stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true;
self.stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true;
fbLinks.append("Some text")
fbLinks.append("Some other text but longer")
fbLinks.append("Some other text but way longer then the previous was")
fbLinks.append("text again what a surprise")
fbLinks.append("guess what this is a text too")
for link in fbLinks
{
let sw:UIStackView = generateStackedItem(imageName:"bolt",text: link)
stackView.addArrangedSubview(sw)
}
}
func generateText(text:String)->UILabel
{
let textLabel = UILabel()
textLabel.text = NSLocalizedString(text, comment: "")
textLabel.textAlignment = .left
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
return textLabel
}
func generateStackedItem(imageName:String,text:String)->UIStackView
{
let stackView = UIStackView()
stackView.axis = NSLayoutConstraint.Axis.horizontal
stackView.distribution = .fill
stackView.alignment = .center
stackView.spacing = 5.0
let label = generateText(text: text)
//stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.heightAnchor.constraint(equalTo: label.heightAnchor, constant: 5).isActive = true
stackView.isUserInteractionEnabled = true
// create new Tap Gesture Reconizer here
let tap = UITapGestureRecognizer(target: self, action: #selector(didTapCard(sender:)))
stackView.addGestureRecognizer(tap)
return stackView
}
func openLink(link:String){
if let url = URL(string: link) {
UIApplication.shared.open(url)
}
}
#objc func didTapCard (sender: UITapGestureRecognizer) {
if let sv = sender.view as? UIStackView,
let label = sv.arrangedSubviews.first as? UILabel,
let str = label.text {
print("Stack view with:", str, "was tapped!")
}
}
}
Note: That will work, but is not a particularly great way to do it.
A better approach would probably be to create a custom class that has its own stack view with imageView and label... and its own tap gesture recognizer. Then use either closures or protocol / delegate pattern to process the action.

Trying to programmatically add UIScrollView to my App and I keep getting a blank View

Trying to create a UIScrollView and I cant seem to get my labels to appear as I would like them dead center.
lazy var label : UILabel = {
let label = UILabel()
label.text = "center of container view.center of container view"
label.font = UIFont(name: "Bebas Neue", size: 23)!
label.textColor = .black
return label
}()
// Mark: Properties
lazy var contentViewSize = CGSize(width: self.view.frame.width + 1200, height: self.view.frame.height)
// Mark: Views
fileprivate lazy var parentScrollView : UIView = {
var newView = UIView()
newView.translatesAutoresizingMaskIntoConstraints = false
newView.backgroundColor = .black
newView.frame = self.scrollView.bounds
newView.frame.size = contentViewSize
return newView
}()
fileprivate lazy var scrollView : UIScrollView = {
var uiScrollView = UIScrollView(frame: .zero)
uiScrollView.translatesAutoresizingMaskIntoConstraints = false
uiScrollView.frame = view.bounds
uiScrollView.backgroundColor = .gray
uiScrollView.addViewBorder(borderColor: UIColor.gray.cgColor, borderWith: 10, borderCornerRadius: 0)
// uiScrollView.alpha =
uiScrollView.contentSize = contentViewSize
// uiScrollView.autoresizingMask = .flexibleHeight
uiScrollView.showsVerticalScrollIndicator = true
uiScrollView.bounces = true
return uiScrollView
}()
fileprivate lazy var tutorialView : UIStackView = {
var tutView = UIStackView(arrangedSubviews: [label,label,label])
tutView.axis = .horizontal
tutView.backgroundColor = .white
tutView.distribution = .fillEqually
tutView.spacing = 0
return tutView
}()
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(parentScrollView)
parentScrollView.addSubview(tutorialView)
scrollView.widthAnchor.constraint(equalTo:self.view.widthAnchor,multiplier: 0.9).isActive = true
scrollView.heightAnchor.constraint(equalTo:self.view.heightAnchor,multiplier: 0.7).isActive = true
scrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 75).isActive = true
tutorialView.topAnchor.constraint(equalTo: parentScrollView.topAnchor,constant: +10).isActive = true}
It seems that when I add that last constraight with the topAnchor I get a blank screen. When I take that off I actually get the borders between the two views and I am able to do some scrolling.
Any help would be appreciated. Thank you
Did you give a value to the scrollView?
uiScrollView.contentSize.width = 1200
Then give the tutorialView the same width constraint with the other constraints.
NSLayoutConstraint.activate([
tutorialView.widthAnchor.constraint(equalToConstant: 1200),
tutorialView.heightAnchor.constraint(equalTo: uiScrollView.heightAnchor)
])
You have to add tutView.translatesAutoresizingMaskIntoConstraints = false when giving layout constraints in closure of tutorialView and also there are some mistakes in your code. So included some changes in your code and check updated code:
lazy var label : UILabel = {
let label = UILabel()
label.text = "center of container view.center of container view"
label.font = UIFont(name: "Bebas Neue", size: 23)!
label.textColor = .green
return label
}()
// Mark: Properties
lazy var contentViewSize = CGSize(width: self.view.frame.width + 1200, height: self.view.frame.height)
// Mark: Views
fileprivate lazy var parentScrollView : UIView = {
var newView = UIView()
newView.translatesAutoresizingMaskIntoConstraints = false
newView.backgroundColor = UIColor.clear
// newView.layer.borderWidth = 2
// newView.layer.borderColor = UIColor.yellow.cgColor
return newView
}()
fileprivate lazy var scrollView : UIScrollView = {
var uiScrollView = UIScrollView()
uiScrollView.translatesAutoresizingMaskIntoConstraints = false
// uiScrollView.frame = view.bounds
uiScrollView.backgroundColor = .orange
uiScrollView.layer.borderColor = UIColor.blue.cgColor
uiScrollView.layer.borderWidth = 2
uiScrollView.layer.cornerRadius = 0
// uiScrollView.alpha =
uiScrollView.contentSize = contentViewSize
// uiScrollView.autoresizingMask = .flexibleHeight
uiScrollView.showsVerticalScrollIndicator = true
uiScrollView.bounces = true
return uiScrollView
}()
fileprivate lazy var tutorialView : UIStackView = {
var tutView = UIStackView(arrangedSubviews: [label,label,label])
tutView.axis = .horizontal
tutView.backgroundColor = .red
tutView.distribution = .fill
tutView.translatesAutoresizingMaskIntoConstraints = false
return tutView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(parentScrollView)
parentScrollView.addSubview(tutorialView)
scrollView.widthAnchor.constraint(equalTo:self.view.widthAnchor,multiplier: 0.9).isActive = true
scrollView.heightAnchor.constraint(equalTo:self.view.heightAnchor,multiplier: 0.7).isActive = true
scrollView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 25).isActive = true
parentScrollView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
parentScrollView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10).isActive = true
parentScrollView.heightAnchor.constraint(equalToConstant: 200).isActive = true
parentScrollView.widthAnchor.constraint(equalToConstant: 200).isActive = true
// scrollView.layer.borderWidth = 2
// scrollView.layer.borderColor = UIColor.blue.cgColor
tutorialView.heightAnchor.constraint(equalTo: parentScrollView.heightAnchor).isActive = true
tutorialView.widthAnchor.constraint(equalToConstant: 1200).isActive = true
}

Thread 1: signal SIGABRT error in AppDelegate when add subView to main view

App crash when add some views (i. e. UIView, UITextView, UIImageView, ...) to main view
import UIKit
class ViewController: UIViewController {
let textview: UITextView = {
let textview2 = UITextView()
textview2.text = "Hello World"
textview2.font = UIFont.boldSystemFont(ofSize: 18)
textview2.textAlignment = .center
return textview2
}()
override func viewDidLoad() {
super.viewDidLoad()
textview.translatesAutoresizingMaskIntoConstraints = false
textview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
textview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
view.addSubview(textview)
}
}
How to create views by programmatically?
Edit: I forgot to add the view before setting constraints. So you need to set constraints after adding subviews.
You need to add subview first view.addSubview(textview) before adding constraints and set height and width also for textview as you can see updated code:
import UIKit
class ViewController: UIViewController {
let textview: UITextView = {
let textview2 = UITextView()
textview2.text = "Hello World"
textview2.font = UIFont.boldSystemFont(ofSize: 18)
textview2.textAlignment = .center
return textview2
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textview)
textview.translatesAutoresizingMaskIntoConstraints = false
textview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
textview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
textview.widthAnchor.constraint(equalToConstant: 150).isActive = true
textview.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
}
First you need to add view.addSubview(textview) then add constraints.
import UIKit
class testViewController: UIViewController {
let textview: UITextView = {
let textview2 = UITextView()
textview2.text = "Hello World"
textview2.font = UIFont.boldSystemFont(ofSize: 18)
textview2.textAlignment = .center
return textview2
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textview)
textview.translatesAutoresizingMaskIntoConstraints = false
textview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
textview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
// you need to specify height and width constraints as well otherwise UITextView will not appear
textview.widthAnchor.constraint(equalToConstant: 100).isActive = true
textview.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
}
You must set constraints after view.addSubview
like this :
import UIKit
class ViewController: UIViewController {
let textview: UITextView = {
let textview2 = UITextView()
textview2.text = "Hello World"
textview2.font = UIFont.boldSystemFont(ofSize: 18)
textview2.textAlignment = .center
return textview2
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textview)
textview.translatesAutoresizingMaskIntoConstraints = false
textview.heightAnchor.constraint(equalToConstant: 100).isActive = true
textview.widthAnchor.constraint(equalToConstant: 200).isActive = true
textview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
textview.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}

Set Constraints Programmatically

I am trying to add an UIView with a label, and want to set constraints to place the label in the center horizontally as well as vertically. But the code doesn't place it as I want. Below is the code. The label is presented on the top left hand corner of the screen instead of the center of the screen.
class TestViewController: UIViewController {
var title = UIView()
override func viewDidLoad() {
super.viewDidLoad()
func presentTitle ()
}
func presentTitle () {
title.backgroundColor = UIColor.black
title.textColor = UIColor.white
title.font = UIFont(name: "Helvetica", size: 30)
title.textAlignment = .center
title.backgroundColor = .lightGray
title.numberOfLines = 1
title..text = vmTitleTransferredFromTaskAnalysisDetail!
self.view.addSubview(title)
title.translatesAutoresizingMaskIntoConstraints = false
title.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
title.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor).isActive = true
title.eadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
title.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
self.view = title
}
}

How do I collapse UIViews programatically?

I'm working on my first IOS app and have run into an issue. I have a quite elaborate programmatic autoloyout UI that responds to user interaction. When a keyboard is shown certain Views must be collapsed, others moved and others spawned into existence based on a few conditions.
Now in it's default state no autolayout errors occur. But once things start moving it all comes apart. A few of the issues have to do with images retaining their height, while their view's heigconstriant is set to 0. Now I do have .scaleToFill enabled.
I have looked into stackViews however since most of my Views are of a different size with different nested UI elements stackviews do now appear to solve my issues. But I would certainly like some input on that.
Now my questions is: How do I collapse UIView and UIImageviews dynamically and programatically?
Now I don't mind typing out a lot of constraints manually, as long as it works.
Here are the constraints of the Views in question(there are more)
func setUpLayout() {
// SuggestionCloud
suggestionCloud.setConstraints(
topAnchor: textView.bottomAnchor, topConstant: 0,
bottomAnchor: bottomMenu.topAnchor, bottomConstant: 0,
trailingAnchor: view.trailingAnchor, trailingConstant: -10,
leadingAnchor: view.leadingAnchor, leadingConstant: 10)
print("Suggestion View frame :\(suggestionCloud.frame)")
//WEIGHT_IMAGE_VIEW
weigtImageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
weigtImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
weigtImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
weigtImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
weigtImageView.addSubview(weightLabel);
print("Weight Image View \(weigtImageView.frame)")
//WEIGHT_LABEL
weightLabel.trailingAnchor.constraint(equalTo: weigtImageView.trailingAnchor, constant: -30).isActive = true;
weightLabel.leadingAnchor.constraint(equalTo: weigtImageView.leadingAnchor, constant: 25).isActive = true;
weightLabel.heightAnchor.constraint(equalTo: weigtImageView.heightAnchor, multiplier: 1).isActive = true;
//TEXT_VIEW
textView.topAnchor.constraint(equalTo: weigtImageView.bottomAnchor).isActive = true;
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true;
textView.heightAnchor.constraint(equalToConstant: 100).isActive = true;
textView.addSubview(nameTextField)
textView.addSubview(tagTextField)
textView.addSubview(setButtonView)
//TAG_CONTROLLER
tagController.heightAnchor.constraint(equalToConstant: 110).isActive = true;
tagController.topAnchor.constraint(equalTo: self.weigtImageView.bottomAnchor).isActive = true;
tagController.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant : 10).isActive = true
tagController.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -10).isActive = true
//SET_BUTTON_VIEW
setButtonView.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true;
setButtonView.bottomAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true;
setButtonView.trailingAnchor.constraint(equalTo: textView.trailingAnchor).isActive = true;
setButtonView.widthAnchor.constraint(equalToConstant: 110).isActive = true;
//NAME_TEXT_FIELD
nameTextField.trailingAnchor.constraint(equalTo: setButtonView.leadingAnchor, constant: -5).isActive = true
nameTextField.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: 10).isActive = true
nameTextField.topAnchor.constraint(equalTo: textView.topAnchor, constant: 13).isActive = true
nameTextField.heightAnchor.constraint(equalToConstant: 31).isActive = true
nameTextField.layer.cornerRadius = 8
nameTextField.backgroundColor = .white;
//TAG_TEXT_FIELD
tagTextField.trailingAnchor.constraint(equalTo: setButtonView.leadingAnchor, constant: -5).isActive = true
tagTextField.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: 10).isActive = true
tagTextField.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: -13).isActive = true
tagTextField.heightAnchor.constraint(equalToConstant: 31).isActive = true
tagTextField.layer.cornerRadius = 8
tagTextField.backgroundColor = .white
here's the viewcontrollers setup:
class UIScaleControllerVew: UIViewController, UITextFieldDelegate, SuggenstionCloudDelegate {
let weigtImageView : UIImageView = {
var imageView = UIImageView(image: UIImage(named: "scaleVisorShadow"));
imageView.contentMode = .scaleToFill
imageView.translatesAutoresizingMaskIntoConstraints = false;
return imageView
}()
let weightLabel : UILabel = {
let label = UILabel()
label.text = "135 gr"
label.font = UIFont(name: "Avenir-Light", size: 50.0)
label.textAlignment = .right
label.translatesAutoresizingMaskIntoConstraints = false
return label
}();
let textView : UIView = {
var view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false;
return view;
}();
let setButtonView : UIImageView = {
var imageView = UIImageView(image: UIImage(named: "setButton"))
imageView.translatesAutoresizingMaskIntoConstraints = false;
return imageView;
}();
let nameTextField : UITextField = {
var textField = UITextField();
textField.tag = 2;
textField.translatesAutoresizingMaskIntoConstraints = false;
textField.addTarget(self, action: #selector(nameFieldEditingChanged(_:)), for: UIControl.Event.editingChanged)
return textField;
}();
let tagTextField : UITextField = {
var textField = UITextField();
textField.tag = 1;
textField.translatesAutoresizingMaskIntoConstraints = false;
textField.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: UIControl.Event.editingChanged)
return textField;
}();
let bottomMenu : UIView = {
var view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false;
return view;
}();
let saveButton : UIButton = {
let button = UIButton()
button.setImage(UIImage(named: "save"), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false;
return button
}();
let microPhoneButton : UIButton = {
let button = UIButton()
button.setImage(UIImage(named: "microPhone"), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false;
return button;
}();
let suggestionCloud : SuggenstionCloud = {
let cloud = SuggenstionCloud(image: UIImage(named: "suggestionCloud.png"))
cloud.translatesAutoresizingMaskIntoConstraints = false;
return cloud;
}();
let tagController : TagController = {
let tagController = TagController()
tagController.translatesAutoresizingMaskIntoConstraints = false
return tagController;
}()
let scaleModel = ScaleModel.init()
override func viewDidLoad() {
super.viewDidLoad()
print("UIScaleController_DidLoad")
tagTextField.delegate = self
nameTextField.delegate = self;
suggestionCloud.delegate = self;
view.backgroundColor = UIColor(hexString: "8ED7F5")
view.addSubview(weigtImageView)
view.addSubview(textView)
view.addSubview(bottomMenu);
view.addSubview(suggestionCloud)
view.addSubview(tagController)
tagController.isHidden = true;
setUpLayout()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
var didSetUpSuggestionCloud = false
var didSetUpTagController = false
override func viewDidLayoutSubviews() {
guard !self.didSetUpTagController else {
return
}
guard !self.didSetUpSuggestionCloud else {
return
}
self.didSetUpSuggestionCloud = true
self.didSetUpTagController = true
};
and here's the problematic code:
#objc func keyboardWillShowNotification(notification: Notification ) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
// collapse and hide bottom view
bottomMenu.contentMode = .scaleToFill;
bottomMenu.heightAnchor.constraint(equalToConstant: 0).isActive = true;
bottomMenu.isHidden = true
// collapse and hide top view
weigtImageView.contentMode = .scaleToFill;
weigtImageView.heightAnchor.constraint(equalToConstant: 0).isActive = true;
weigtImageView.isHidden = true;
// spawn my tag view
tagController.topAnchor.constraint(equalTo: self.textView.bottomAnchor).isActive = true;
tagController.bottomAnchor.constraint(equalTo: suggestionCloud.topAnchor).isActive = true
tagController.isHidden = false;
// set textviews new constraints
textView.bottomAnchor.constraint(equalTo: tagController.topAnchor).isActive = true;
// set middleView's new constraints
suggestionCloud.topAnchor.constraint(equalTo: tagController.bottomAnchor).isActive = true;
suggestionCloud.bottomAnchor.constraint(equalTo: bottomMenu.topAnchor, constant: -keyboardSize.height).isActive = true
self.view.layoutIfNeeded()
}
}
Now there are so many unexpected things happening that i'm positive that my approach to this is just wrong conceptually.
Please let me know where I need to look for a solution.
Here are e few pictures of what is happening so far:
So when the keyboard is up:
The weightView is collapsed: suggestioncloud and text are moved up.
If a tag is added a new view called tagController needs to be places between the texView and the suggesitonCloud. Lastyl the keybaord needs to be collapsed again.
Ill add some sscreenshots
One thing that you could look at is duplicate constraints.
Every time you call weigtImageView.heightAnchor.constraint(equalToConstant: 0).isActive = true you are creating a new constraint. This does not automatically replace any previous height constraints that are active.
To replace a constraint, you need to keep a reference to it, deactivate it, and then activate a new one (and optionally assign it the the variable you use to keep a reference).
Stack views
Stack views could be helpful in your situation, because they automatically collapse views that have isHidden set to true. I think that as long as the direct subviews of the StackView have an intrinsic content size (e.g. correct internal constraints), they should be placed correctly by the StackView.
If you do not have a strong reference to your views to be released then it is enough to execute this:
if view2Breleased.superview != nil {
view2Breleased.removeFromSuperview()
}
The view will then disappear and be released from memory.
If you don't know what a strong reference is then for the time being, just try the code I wrote. The views will disappear anyway.
(Strong reference means you have assigned the view to a variable which survives the execution of the code view2Breleased.removeFromSuperview() and the exit from the function call where the code view2Breleased.removeFromSuperview() is.)
You can change the constant of the heightAnchor constraint like so:
import Foundation
import UIKit
class TestController : UIViewController {
var myViewHeightConstraint : NSLayoutConstraint!
let myView : UIControl = {
let newView = UIControl()
newView.translatesAutoresizingMaskIntoConstraints = false
newView.backgroundColor = .red
return newView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
self.myView.addTarget(self, action: #selector(viewClicked), for: .touchUpInside)
self.myViewHeightConstraint = myView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor)
setup()
}
func setup(){
view.addSubview(myView)
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
myView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
self.myViewHeightConstraint.isActive = true
}
#objc func viewClicked() {
self.myViewHeightConstraint.constant = -self.myView.frame.size.height
}
}
In my example, I set the constant to minus the height of the view's frame height, which effectively collapses it.

Resources