Swift Safe Area Layout not activating properly - swift

I am learning some auto layout programatically and I want to add a button on the bottom part of the screen, just above the safe area.
I know the code is working, because I tested it in another project, I think it is a conflict because I get to this viewController from another one.
The code for my button
private let previousButton : UIButton = {
let button = UIButton(type: .system)
button.setTitle("Prev", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
The code for setting up my constraints
fileprivate func setupBottomControls() {
view.addSubview(previousButton)
previousButton.backgroundColor = .red
view.addSubview(previousButton)
NSLayoutConstraint.activate([
previousButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
previousButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
previousButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
previousButton.heightAnchor.constraint(equalToConstant: 50)
])
}
Like I said this code is working in another project but I think it is in conflict because of how I called this viewController.
This is a code from the first view controller that make the new viewController(GettingStartedController) to be shown, here it will be the button mentioned above.
func switchVC(){
//enter GettingStarted controller
let controller = GettingStartedController()
view.addSubview(controller.view)
present(UINavigationController(rootViewController: controller), animated: true,completion: nil) //used when no animation is present
}
I think the problem is here any ideas on how to change the call to the GettingStartedController so that will see the Safe Area the right way?

Check my code solution. I added your function to the button when it is tapped and it now presents the GettingStartedController():
private let previousButton : UIButton = {
let button = UIButton(type: .system)
button.setTitle("Prev", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(switchVC), for: .touchUpInside)
return button
}()
fileprivate func setupBottomControls() {
view.addSubview(previousButton)
previousButton.backgroundColor = .red
view.addSubview(previousButton)
NSLayoutConstraint.activate([
previousButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
previousButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
previousButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
previousButton.heightAnchor.constraint(equalToConstant: 50)
])
}
#objc func switchVC(){
//enter GettingStarted controller
let controller = GettingStartedController()
present(UINavigationController(rootViewController: controller), animated: true,completion: nil) //used when no animation is present
}

Related

Push View Controller Swift

I am trying to push to a new view controller when I click the quiz button I implemented. I set it up as below:
quizButton = UIButton()
quizButton.setTitle(" Quiz ", for: .normal)
quizButton.backgroundColor = .lightGray
quizButton.layer.cornerRadius = 9
quizButton.translatesAutoresizingMaskIntoConstraints = false
quizButton.addTarget(self, action: #selector(takeQuiz), for: .touchUpInside)
view.addSubview(quizButton)
and I defined the function takeQuiz as below, where there is a separate view controller called QuizViewController:
#objc func takeQuiz() {
let newViewController = QuizViewController()
navigationController?.pushViewController(newViewController, animated: true)
}
I'm not sure if it was necessary for me to use delegates here, since I am not trying to relay any information from one view controller to the other. Let me know, thanks in advance.

UIButton doesn't work in child view controller

UIButton gestures doesn't recognize in child view controller.
UIButton add targer work (button get target action)
User interaction is turned on everywhere, button size is okay. I try to set childVC as main, and then all work good, debug view hierarchy said that button view over other elements. IDK where is problem. I can provide more code, just tell me.
Add target code:
view.buttonOfLanguageFromTranslate.addTarget(self, action: #selector(self.openDetailView(_:)), for: .touchDown)
Add child VC code:
let childVC = ChildVC()
view.addSubview(childVC.view)
self.addChild(childVC)
childVC.didMove(toParent: self)
childVC.view.translatesAutoresizingMaskIntoConstraints = false
self.view.isUserInteractionEnabled = true
self.childVC = childVC
Button initialization:
var button: UIButton = {
let button = UIButton()
button.setTitle("Title", for: .normal)
button.setTitleColor(.black, for: .normal)
button.setTitleColor(.green, for: .selected)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
The problem was with
childVC.translatesAutoresizingMaskIntoConstraints = false
(in mainVC)
When i remove it, childVC recognise my tap
and i dont set additional size for childVC, view of childVC is display correct but not childVC. (as i think)

Navigation Controller not releasing memory, memory leak?

Ive created a navigation which pushes a view controller that contains an image view and a button which adds the same view controller each time the button is tapped. After each tap the memory grows and after each back tap the memory is not released despite deinit being called. There is nothing in the code that points to a memory leak is there something I am missing thank you?
complete project repository
class ViewController: UIViewController {
lazy var nextButton:UIButton? = {
let button = UIButton(type: .roundedRect)
button.setTitle("Next", for: .normal)
button.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.red
return button
}()
lazy var imageView:UIImageView? = {
let image = #imageLiteral(resourceName: "DJI_0014")
let imageView = UIImageView(image: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
guard let imageView = self.imageView, let nextButton = self.nextButton else{
print("imageView, nextButton are nil")
return
}
self.view.backgroundColor = UIColor.white
self.view.addSubview(imageView)
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo:self.view.topAnchor),
imageView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
imageView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
imageView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)])
view.addSubview(nextButton)
NSLayoutConstraint.activate([nextButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
nextButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),nextButton.heightAnchor.constraint(equalToConstant: 200),nextButton.widthAnchor.constraint(equalToConstant: 200)])
}
#objc func nextButtonTapped(){
print("next button tapped")
self.navigationController?.pushViewController(ViewController(), animated: true)
}
deinit {
print("view controller is deinitialized")
}
}
Ive viewed other questions listed below and tried to adopt their suggestions but none of them seemed to help
Navigation arc memory not released
Memory leak issue in navigation controller
Finally, I have identified the problem, which is from the navigationBar:
navigationController?.setNavigationBarHidden(true, animated: false)
This code will remove all the issues on large memory residues. Other parts of codes are fine. and in this situation, all memory will keep around 19M all the time.
I tried to use a navigationDelegate to do the transition and found there is a crash overlooked by the system and stated that if repeating push vc will make NavigationBar not layout well. So I turn it hidden and the problem has gone. But if you do need navigationBar or its animation, there would be a lot of work to do here.
But the memory issue has been found.

how to change bordercolor when Button.isHighlighted

I wonder how I get my border around my UIButton to change opacity together with the text inside it, when it is either clicked or highlighted.
My logic tells me, that it should be something like this.. but it doesn't seem to work:
//BTN STYLING
btnstd.layer.cornerRadius = 5
btnstd.layer.borderWidth = 1.5
btnstd.layer.borderColor = UIColor.white.cgColor
//Change bordercolor when highlighted
if(btnstd.isHighlighted) {
btnstd.layer.borderColor = UIColor(white:1,alpha:0.3).cgColor
}
This is by the way put inside my ViewDidLoad() function
The actions you are looking for are .touchDown and anything .touchUp:
override func viewDidLoad() {
super.viewDidLoad()
theButton.setTitle("Normal", for: .normal)
theButton.setTitle("Highlighted", for: .highlighted)
theButton.layer.borderColor = UIColor.red.cgColor
theButton.layer.borderWidth = 1
theButton.addTarget(self, action: #selector(startHighlight), for: .touchDown)
theButton.addTarget(self, action: #selector(stopHighlight), for: .touchUpInside)
theButton.addTarget(self, action: #selector(stopHighlight), for: .touchUpOutside)
}
func startHighlight(sender: UIButton) {
theButton.layer.borderColor = UIColor.green.cgColor
theButton.layer.borderWidth = 1
}
func stopHighlight(sender: UIButton) {
theButton.layer.borderColor = UIColor.red.cgColor
theButton.layer.borderWidth = 1
}
It depends on what you are trying to do.
Case #1: You want this change to happen when the button is highlighted, but in a normal state have a different set of properties.
let theButton = UIButton()
// set common properties and layout code
theButton.setTitle("Normal", for: .normal)
theButton.setTitle("Highlighted", for: .highlighted)
In addition, you have setTitleColor(), setAttributedTitle, setTitleShadowColor(), setImage(), and setBackgroundImage() that you can code directly.
Border color in this case would need a subclass (not an extension, you want public properties) where you will check self.layer.hitTest() after wiring up a tap gesture on self.
Case #2: You want the button state to change when clicked, and stay changed.
You are part way there. If you supply the button in IB, make sure you add an IBAction for event touchUpInside. If you are working in code, here's the Swift 3 syntax.
theButton.addTarget(self, action: #selector(changeButton), for: .touchUpInside)
func changeButton(sender: UIButton) {
sender.setTitle("New Title", for: .normal)
sender.layer.borderColor = UIColor.red.cgColor
}
My preference (but only that) is to more strongly-type the sender (I think that's the correct term) for my actions. I'm sure there are pros and cons for using a specific sender (like UIButton) over AnyObject, but in this case I think the biggest reason is you don't need to force-cast the sender to UIButton.

Swift UIButton not appearing on screen

I have a view in my tabbar controller where I would like to show a button. I create this button programmatically based of a condition, therefore I use the following code but nothing is appearing:
override func viewDidLoad() {
super.viewDidLoad()
if !Settings.getIsConnected() {
notConnected()
}
}
func notConnected() {
let connectBtn = UIButton(frame: CGRect(x: self.view.center.x, y: self.view.center.y, width: 200, height: 45))
connectBtn.setTitle("Connect", forState: .Normal)
connectBtn.addTarget(self, action:#selector(self.pressedConnect(_:)), forControlEvents: .TouchUpInside)
self.view.addSubview(connectBtn)
print("Button created")
}
func pressedConnect(sender: UIButton!) {
}
I am clueless on what I am doing wrong. Anyone got suggestions? Cause it does print out "Button created" so it definitely runs the code inside the noConnected() method.
Add a background color to your UIButton and add a tint color to the title. This will resolve the problem
Try moving the code to viewDidAppear and see if the button is showing up.
The frame is not correctly set when in viewDidLoad. Use the method viewDidLayoutSubviews for the earliest possible time where the frame is correctly setup for a ViewController.
With this code change, you will need some additional logic for when your button should be added as a subview though.
A programmatically created button may not show up because of more reasons, e.g:
the tint color is not set
the background color is not set
the button is not added to the view hierarchy
the button is hidden
In your case, you should change the tint color or the background color of your button.
E.g.:
Swift 4.2:
private lazy var connectButton: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = .green
button.setTitleColor(.black, for: .normal)
button.setTitle(NSLocalizedString("Connect", comment: ""), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(connectButton)
}
You can re-check the button properties in the storyboard that it is not hidden.