I've got this collection view, and I want to be able to delete a cell by dragging it in the trash bar button on the right of the bar.
I don't understand how to make the button able to receive a drop,
if it was a UIView I can do
addInteraction(UIDropInteraction(..))
but since it is a button I can't act this way.
Someone can help me?
You can try creating a custom view and add interactions to it. And finally, add that to the rightBarButtonItem. Something on the lines of:
func viewDidLoadForBarButton() {
let customView = UIView() //Add your custom UIView() here
customView.sizeToFit()
let dropInteraction = UIDropInteraction(delegate: self)
customView.addInteraction(dropInteraction)
let barButton = UIBarButtonItem(customView: customView)
self.navigationItem.rightBarButtonItem = barButton
}
Let me know if it works.
Related
In my app, the first ViewController appears with right navigation bar items. I want to show different bar items on right side in child VC which is appeared by pushing. The items in the first VC shows fine, but the second doesn't. The bar button shows for a second when the VC disappeared.
// The things the first VC did
navigationItem.setHidesBackButton(true, animated: true)
navigationController?.navigationBar.tintColor = .gray600
let stackView = UIStackView()
stackView.addArrangedSubviews(views: [registerButton, notificationButton])
stackView.spacing = 16
let rightBarButton = UIBarButtonItem(customView: stackView)
navigationController?.navigationBar.topItem?.rightBarButtonItem = rightBarButton
// The things the second did
navigationController?.navigationBar.tintColor = .gray600
navigationController?.navigationBar.topItem?.backButtonTitle = ""
navigationController?.navigationBar.backIndicatorImage = .back
navigationController?.navigationBar.backIndicatorTransitionMaskImage = .back
let rightBarButton = UIBarButtonItem(customView: editButton)
navigationController?.navigationBar.topItem?.rightBarButtonItem = rightBarButton
They did almost same things but the second doesn't work.
Here is the gif file i recorded. You can see Edit button for a second when the second VC disappeared. I tried to find the clues but i couldn't. Please check it and give me any comments. Thank you.
Delete the phrase navigationController?.navigationBar.topItem everywhere it appears, and never use it again, ever. It will totally break the navigation controller — as you yourself have demonstrated.
The only navigation item a view controller can talk to is its own navigationItem property. Thus the first vc is much more correct than the second vc, and so it works much better than the second vc.
you should not set a button and its title by using "topItem", instead you should set them by using navigationItem's rightBarButtonItem.
let rightBarButton = UIBarButtonItem(customView: editButton)
navigationItem.rightBarButtonItem = rightBarButton
let backButton = UIBarButtonItem(...)
navigationItem.leftBarButtonItem = backButton
Essentially I have a UIButton created in StoryBoards that I would like to drag into the navigation bar. This UIButton has an action associated with it when touched but all touch events stop working when I drag this UIButton into the navigation bar.
Is there additional code I need to the IBAction item when doing this?
One of the main reasons I want to add a UIButton instead of a BarButtonItem to the navigation bar is simply because it allows me to add a background color and curve the edges of the button.
I don't think you can do it in the storyboard. You have to do it in code, using the init(customView:) initialiser.
let myCustomButtonWithBackgroundsAndStuff = UIButton(type: .custom)
...
// this is the equivalent of connecting the IBAction, in code form, in case you didn't know
myCustomButtonWithBackgroundsAndStuff.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
let barButtonItem = UIBarButtonItem(customView: myCustomButton)
navigationItem.rightBarButtonItem = barButtonItem
// or append to rightBarButtonItems if you have other bar button items
...
#objc func buttonAction() {
...
}
I'm a beginner in swift and trying to learn UIPickerView which has done button to close after the selection from the picker view. I have following code to add the tool bar and the done button to the picker as a toolbar in subview. It shows up as a blank black toolbar (attached screenshot)
let toolBar = UIToolbar()
toolBar.barStyle = .black
toolBar.sizeToFit()
let doneBtn = UIBarButtonItem.init(title: "Done", style: .plain, target: self, action: #selector(self.closePicker))
toolBar.items = [doneBtn]
toolBar.isUserInteractionEnabled = true
picker.addSubview(toolBar)
Picker is the outlet for UIPickerView in my controller. What am I doing wrong? I referred to other questions but they dont seem to solve my problem. Any suggestions?
You are wrong at this line:
picker.addSubview(toolBar)
Picker is not supposed to have any subviews - it's a comprehensive view by itself and there is no area in it to accommodate anything in addition.
Instead you need to add both the picker and the toolbar on the same view and align them next to each other
let toolBar = UIToolbar()
...configure your toolbar here...
guard let superview = picker.superview else { return }
superview.addSubview(toolBar)
toolBar.translateAutoresizingMaskIntoConstraints = false
NSLayoutConstraints.activate([
toolBar.topAnchor.constraint(equalTo: superview.topAnchor),
toolBar.leftAnchor.constraint(equalTo: superview.leftAnchor),
toolBar.rightAnchor.constraint(equalTo: superview.rightAnchor),
toolBar.bottomAnchor.constraint(equalTo: picker.topAnchor)
])
You should not add toolBar as subView of picker.
You should set the toolBar as inputAccessoryView of textField.
As I searched for this problem I got that the common way (also easiest way) to achieve what you want is Using dummy textField.
It means create a textField at the exact frame of button and hide it, when user touches the button make the textField firstResponder.
#IBAction func pickerButtonClicked(_ sender: Any) {
self.pickerViewTextField.becomeFirstResponder
}
I'm testing an app and I discovered that when double tapping the back button, it automatically pops to root view controller of the navigation controller. There is no code anywhere that does this explicitly and I was wondering if this is the default behavior of the back button in a navigation controller.
I've tested the same thing in another app and the issue wasn't there, so the only thing that explains this is that something else is triggering that popToRoot and I can't figure out what.
Sorry, but I cannot post the code here. Just want your opinion on this.
Thanks in advance!
As I commented above at Glenns answer, dispatching the popViewController into the main thread might be a problem because it will be executed also when a double tap is recognized. Maybe this is a slightly more "stable" solution:
private func setupBackButton() {
let myBackButton = UIButton(type: .custom) // or whatever
// setup title, image etc.
let myCustomBackButtonItem = UIBarButtonItem(customView: myBackButton)
self.navigationItem.leftBarButtonItem = myCustomBackButtonItem
// Create gesture recognizers for single and double tap:
let singleRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.singleTap))
singleRecognizer.numberOfTapsRequired = 1
let doubleRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.doubleTap))
doubleRecognizer.numberOfTapsRequired = 2
// single tap should only fire if double tap is not recognized
singleRecognizer.require(toFail: doubleRecognizer)
myBackButton.addGestureRecognizer(singleRecognizer)
myBackButton.addGestureRecognizer(doubleRecognizer)
}
#objc private func singleTap() {
self.navigationController?.popViewController(animated: true)
}
#objc private func doubleTap() {
self.navigationController?.popToRootViewController(animated: true)
}
When I saw this question, I implemented the idea onto my current project, and it worked, thanks for this. So an idea to do this is have a custom back button. I could post the whole code to this but that would make it a spoonfeeding. Anyways, here goes the steps:
Make a UIButton and make it your custom back button UIBarButtonItem in your navigationController's navigationBar if you ever use one.
The selector would be obviously like this, don't mind much the code inside, cause this is taken out of my project, but you get the idea:
func back() {
if let navCon = self.navigationController {
navCon.popViewController(animated: true)
}
}
And for the double tap, you'll need a tapGesture for that. I have this one declared like so:
private lazy var doubleTapGesture: UITapGestureRecognizer = {
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.doubleTap))
gesture.numberOfTapsRequired = 2
return gesture
}()
and add that to your button. Selector would be like this:
#objc private func doubleTap() {
self.navigationController?.popToRootViewController(animated: true)
}
VOILA! Works smoothly. Easy, right? I hope this helps!
Thank you for all your answers but my issue was that I DIDN'T want that behavior, my post was misinterpreted and I'm sorry for that.
Otherwise, I solved myself the problem. There was a subview added to navigation controller's navigation bar which was hidden up, below the bar. And somehow, that subView had interaction enabled even if it was below. So I disabled interaction when hidden. That's all.
I'm trying to add TopView in my application, it will be the same for each views. I do it like this
let vcTopMenu = storyboard?.instantiateViewControllerWithIdentifier("TopMenu")
let win:UIWindow = UIApplication.sharedApplication().delegate!.window!!
win.rootViewController = vcTopMenu
win.makeKeyAndVisible()
But when I add other viewControllers (I do it transparent) I can see buttons of TopView, but I can't click on it. It's a code from TopView
override func viewDidLoad()
{
super.viewDidLoad()
print("loaded")
}
#IBAction func btn(sender: AnyObject)
{
print("do something")
}
I see "loaded", but clicking doesn't work, how can I click through view? Thanks!
If I understand your question correctly, you're placing a translucent/transparent UIView on top of another UIView with a button you want to press?
The topmost UIView by default receives the touches. More on this here.
It's not a very standard/practical way to do things, but if you absolutely must, check out this answer: https://stackoverflow.com/a/4010809/4396258