Swift tvOS - TabBar Trailing Accessory View Focus - swift

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.

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 NavBar Hide NavBarItem

Inside of my view controller I have a navBar with an item on the left side and right side. I also have 2 buttons inside of the view controller. I have it so each button does different functionality. I also have the swift file connected to the view.
My issue is that when I do either of the code below inside of my button actions the NavBar Items do not change. I don't know how to remove and add the item back, I also dont understand what Im doing wrong.
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.navigationItem.rightBarButtonItem?.tintColor = UIColor.clear
self.navigationItem.rightBarButtonItem?.isEnabled = true
self.navigationItem.rightBarButtonItem?.tintColor = UIColor.red
Connect Navigation Bar from storyboard to View Controller Class
#IBOutlet var navBar: UINavigationBar!
This will hide Button
navBar.topItem?.rightBarButtonItem?.isEnabled = false
navBar.topItem?.rightBarButtonItem?.tintColor = UIColor.clear
This will show Button
navBar.topItem?.rightBarButtonItem?.isEnabled = true
navBar.topItem?.rightBarButtonItem?.tintColor = UIColor.red
Sorry, i can't make comment due to low reputetion. Which IDE are you using?
The answer of #dharmesh works, if you create the button programmatically:
let btn = UIButton(type: .system)
btn.setTitle("Indietro", for: btn.state)
btn.addTarget(self, action: #selector(annulla), for: .touchUpInside)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: btn)
If you use the one from the IDE it depends on the IDE itself to store the values to hide or change it

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

UITapGestureRecognizer works first time, but not second time

[Greatly simplified]
I'm following a "Let's Build That App" YouTube series on Firebase 3. It's from 2016, so I've had to rework some of the code since Swift has evolved since then, but mostly it's a useful tutorial.
But, I'm stuck on something.
The red box is intended to be a custom titleView with an Image and Name, but I've simplified it to try to find the problem.
viewWillAppear calls setupNavbar which sets up the navbar.titleView:
func setupNavbar() {
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 300, height: 40)
titleView.backgroundColor = .red
let containerView = UIView() // for the Image and Label, later
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.backgroundColor = .green
// left, top, width, height anchors equal to same for titleView
containerView.leftAnchor.constraint(equalTo: titleView.leftAnchor)
// top, width, height are similar
titleView.addSubview(containerView)
self.navigationItem.titleView = titleView
let recognizer = UITapGestureRecognizer(target: self, action: #selector(showChatController))
titleView.addGestureRecognizer(recognizer)
}
The selector's function is:
#objc func showChatController() {
let chatController = ChatLogTableViewController()
navigationController?.pushViewController(chatController, animated: true)
}
The class ChatLogTableViewController has just the default viewDidLoad().
First, I'm surprised the box is red, and not green. Why is that?
Second, if I click the red box, the ChatController is loaded, as expected. But, when I click "Back" and return to this screen, the red box is not visible, thus I can no longer tap on it. BUT....If I sign out and sign in/up again, the box is red and I can click it again.
What am I missing?
Update 1: The "+" creates a new controller and presents it.
present(UINavigationController(
rootViewController: NewMessageTableViewController()),
animated: true,
completion: nil)
That controller is currently empty, except for a leftBarButtonItem which is just a barButtonSystemItem (.cancel). Just like "Sign Out", this also "resets" the gesture and it works.
Update 2: Code added upon request.
Update 3: question greatly simplified. Also, if I change the showChatController code to just print ("show Chat Controller"), I can click to my heart's content; the red box and its tap gesture both remain.
So, there is something happening when I ...pushViewController and then come back.
Have you tried to set isUserInteractionEnabled property of the label which you set as the navBar's titleView? I know it's silly but I've missed this a lot of times :)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(YourViewController.titleWasTapped))
titleView.isUserInteractionEnabled = true
titleView.addGestureRecognizer(recognizer)
you can try following things:
1. "User Interaction Enabled" in the UILabel Attributes Inspector in the Storyboard.
2. override func viewDidLoad(animated: Bool) {
super.viewDidAppear(animated)
self.titleView.userInteractionEnabled = true
var tapGesture = titleView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showChatController)))
self.titleView.addGestureRecognizer(tapGesture)
}
func showChatController() {
println("Tap Gesture recognized")
}
Hi #Zonker I've tested your setupNavBar(). It's working fine nothing worng with your code when I press and go back clicking titleView. Reason why you're not getting .green color is you have to give height and width for containerView and big reason is you've put addSubView code below the anchor and there is no .isActive = true in your containerView.leftAnchor.constraint... Please check setupNavBar() code below:
func setupNavbar() {
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 300, height: 40)
titleView.backgroundColor = .red
let containerView = UIView() // for the Image and Label, later
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.backgroundColor = .green
titleView.addSubview(containerView)
// left, top, width, height anchors equal to same for titleView
containerView.widthAnchor.constraint(equalToConstant: 300).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 40).isActive = true
containerView.leftAnchor.constraint(equalTo: titleView.leftAnchor).isActive = true
// top, width, height are similar
self.navigationItem.titleView = titleView
let recognizer = UITapGestureRecognizer(target: self, action: #selector(showChatController))
titleView.addGestureRecognizer(recognizer)
}
It would better if you push your code in github so we can test your code

Displaying buttons with programmatic constraints

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.