Displaying buttons with programmatic constraints - swift

Despite adding constraints on leading and top anchors for my buttons (I am trying to display them in a list), the view displays all of them in the top left corner of the view. I am calling many methods to try to apply the constraints, but none of them seem to be working. Help!
func displayButtonArray(buttons: [UIButton]) {
var previousButton: UIButton = buttons[0]
for (i, button) in buttons.enumerated() {
button.setTitle("SampleButton", for: .normal)
button.setTitleColor(.black, for: .normal)
button.sizeToFit()
let margins = self.view.layoutMarginsGuide
button.leadingAnchor.constraint(equalTo: margins.leadingAnchor)
if i == 1 {
button.topAnchor.constraint(equalTo: margins.topAnchor, constant: CGFloat(5.0))
} else {
button.topAnchor.constraint(equalTo: previousButton.bottomAnchor, constant: CGFloat(10.0))
}
previousButton = button
button.translatesAutoresizingMaskIntoConstraints = false
button.setNeedsUpdateConstraints()
button.setNeedsLayout()
self.view.addSubview(button)
}
self.view.setNeedsUpdateConstraints()
self.view.setNeedsLayout()
self.view.layoutSubviews()
}

As you pointed out as well, constraints are defined but not activated.
One thing I can add is that as it's mentioned by Apple, AutoLayout constraints should be activated all together.
You may activate them one by one but it's more efficient to activate them all together; leading to better performance.

Related

How can I add two images (one at the left and one on the right side) in a button in Xcode programaticly? I need also a title of a button

func setupButtonUI() {
if let detailsImage = UIImage(named: "detalji_icon") {
setImage(detailsImage, for: .normal)
contentHorizontalAlignment = .left
contentVerticalAlignment = .center
}
if let arrowImage = UIImage(named: "posalji_zahtev_black_icon") {
setImage(arrowImage, for: .normal)
contentHorizontalAlignment = .right
contentVerticalAlignment = .center
}
}/this is one of the things I tried, but whit this I get only the second image and its set in the center not right and the left image is hot even there/
UIButton has only one imageView, you can create custom button like in this answer
https://stackoverflow.com/a/43112735/13628690
Found the next solution: Made a custom UIView and added two images and label as a subview of customView. Did the constraints programaticly. Just added UITapGestureRecognizer (addGestureRecognizer) at the entire view and its all elements are clickable. The design and functionality are satisfied.

Swift tvOS - TabBar Trailing Accessory View Focus

The tabbar has a trailingAccessoryView that the documentation indicates can be used for some user actions. However, while I can put a view inside this accessory view, it does not get the focus at any point. Is there a means to allow this view to get the focus when swiping right from the tabbar?
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 30, weight: .bold, scale: .large)
let guideButton = UIButton()
guideButton.setImage(UIImage(systemName: "list.bullet", withConfiguration: symbolConfig), for: .normal)
guideButton.addTarget(self, action: #selector(test), for: .primaryActionTriggered)
guideButton.translatesAutoresizingMaskIntoConstraints = false
tabBar.trailingAccessoryView.addSubview(guideButton)
guideButton.topAnchor.constraint(equalTo: tabBar.trailingAccessoryView.topAnchor).isActive = true
guideButton.trailingAnchor.constraint(equalTo: tabBar.trailingAccessoryView.trailingAnchor, constant: 0).isActive = true
As a note, I have tried setting: tabBar.trailingAccessoryView.isUserInteractionEnabled = true to no effect.
While not an exact answer, I wound up getting around this issue by adding the button to the tabbar's view rather than to the trailingAccessoryView. Not clear why the accessory view wouldn't work, but this does turn out to be a workable answer that does the job just as well.

Disclosure indicator in tableView cell isn't showing

I have added cell.accessoryType = .disclosureIndicator in my cellForRowAt delegate, and I have also ticked it in the viewController UI options under "accessory". I also added margins to the tableView so that it's 0 in relation to the parent view (that is, the device).
I even set cell.accessoryView?.tintColor = UIColor.black in case something was wrong with the color. But, still, I can't see the little arrow on the right side of the cell. I'm using a default cell. And in other viewControllers that I have it works, but in this one it doesn't.
I checked the width for both the cell and the tableview and they are both 375.
It does work if I add a custom image instead, like this:
let img = UIImage.init(named: "arrow")
cell.accessoryView = UIImageView.init(image: img)
But, I want the standard arrow.
Any more tips on what could be the issue here?
If you're targeting iOS 13 this won't work. You can verify on iOS12 but I've faced this very problem earlier this year and the solution was to add a UIButton to the cell constraining it to the trailing side of the screen.
let disclosureButton = UIButton()
disclosureButton.setImage(UIImage(named: "arrow"), for: .normal)
cell.addSubview(disclosureButton)
disclosureButton.translatesAutoresizingMaskIntoConstraints = false
disclosureButton.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
disclosureButton.centerYAnchor.constraint(equalTo: cell.centerYAnchor, constant: 0).isActive = true
disclosureButton.widthAnchor.constraint(equalToConstant: 25).isActive = true
disclosureButton.heightAnchor.constraint(equalToConstant: 25).isActive = true

Swift Safe Area Layout not activating properly

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
}

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.