isUserInteractionEnabled = false still allows double tap gesture - swift

I have created a double tap gesture for my Collection View. When a cell in the Collection View is double tapped i disable user interaction to the cell. This stops me being able to single tap that cell while a process runs. However i can still double tap that cell which runs the process again. I still want double tap to be available for other cells in the collection, i just want to disable it for the cell that is running process. When the process is finished user interaction is turned back on, and hopefully double tap also.
So this is how i define double tap, in viewDidLoad of the View Controller holding the Collection View:
// add gesture recogniser
let doubleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTap.numberOfTapsRequired = 2
doubleTap.delaysTouchesBegan = true
self.collectionView.addGestureRecognizer(doubleTap)
And I'm just switching userInteraction as usual when needed depending on state of process.
cell.isUserInteractionEnabled = false
cell.isUserInteractionEnabled = true
Im not sure how to approach this as if i disable the double tap gesture for the Collection View i cant double tap other cells. And i don't even know how to set it up so that double tap is only available in the cell and not the Collection View.

Disabling isUserInteractionEnabled on any subview of your collectionView will still pass events to the collectionView (superview). So isUserInteractionEnabled disables touch events on all subviews but not on superviews, which in this case is the collectionView.
You have a few options to proceed:
Create a custom UICollectionViewCell and add a UITapGestureRecognizer to handle the double tap internally and then delegate the double tap event.
Within the didDoubleTap method check to see if the cell that you just double tapped is enabled/disabled. You can do this by using indexPathForItemAtPoint: and then cellForItemAtIndexPath:.

You could set isEnabled to false on the gesture recognizer.
You could implement UIGestureRecognizerDelegate and return false from gestureRecognizerShouldBegin.

Related

TapGesturecognizer not working in backgroundview in iphone X 12.1

I have a simple code to add tapgestureRecognizer to dismis ViewController when tap in screen, but it not working only in iPhone X 12.1.
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(closeSharing(_:))))
Note: magicaly, when i add tap gesturecognizer to a new view that constraint equal to view that also not working, but if i constraint the new view not equal to view, that working. Does any one know why?.
You might need to check a couple of things here:
First step make sure that your main view is not covered for example of another top view which will break your tap gesture, so add the gesture to your top view.
Second step Make sure your view that will have the gesture should have the property view.isUserInteractionEnabled = true, otherwise the gesture will not work.
Third step Make sure your view appears when your testing, you might have a problem with constraints, so the view is out of screen bounds, so try giving the view a backgroundColor = .red to see if it exists or not, or you can use View Debugger from xCode.
Example of a working gesture:
let viewToDismiss = UIView(frame:UIScreen.main.bounds)
viewToDismiss.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(closeSharing(_:)))
tap.numberOfTapsRequired = 1
viewToDismiss.addGestureRecognizer(tap)

How can I have a button and scroll view in the same spot?

To build context, my app has a stack of cards (similar to Tinder) that flip and each could contain a lot of text on one side that require a UITextView for scrolling. It's basically a flashcard app, so once the user is done looking at the card, they swipe it away to view the next one.
I'm trying to make it so the user can tap anywhere on the card to flip it, so I added a clear button that fills up the card. My problem is that when the button is at the front, it blocks the text view from being scrollable, and when the button is at the back, the text view blocks it from being pressed.
Is there a way around this somehow to allow for both functionalities?
You can create a UITapGestureRecognizer, like so:
let gesture = UITapGestureRecognizer(target: self, action: #selector(tap(gesture:)))
addGestureRecognizer(gesture)
And the function to trigger:
#objc func tap(gesture: UITapGestureRecognizer) {
print("Tap!")
}
Maybe you can add a UITapGestureRecognizer to the text view itself. Something like:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.didTap(_:)))
textView.addGestureRecognizer(tapGesture)
#objc func didTap(_ gesture: UITapGestureRecognizer) {
// Handle the tap
}
did you try a tableView or a collectionView, you can customize your cell to look like a card then when a user clicks the cell it will flip or present a popup view, thats easier.

Tap gesture on UILabel beside a UIPageControl not working

I have a UILabel on both sides of a UIPageControl, as pictured below:
I found that tapping on the sides of the UIPageControl the dot would progress, ie not on my arrows and not triggering a method of mine. But nothing else would change, so I set isUserInteractionEnabled to false on the UIPageControl.
I connected (via UITapGestureRecognizer) another UILabel above and it launches a method fine.
However the UILabels, beside the UIPageControl, will not work. NOTE: I do have isUserInteractionEnabled set to true on this element. (I even temporarily changed the element to a UIButton and it wouldn't work either - so I reverted back to my UILabel.)
So, is there a way to add a UILabel to the side of a UIPageControl that gets triggered? Alternately, can the invisible objects (while tapping on the left or right of the UIPageControl - like in my second sentence) be connected to a custom method?
UPDATE:
I've added another separate modal (same title label, buttons, but no collection view and no page control). Again it won't respond when I press the label in the centre, but I temporarily am using the title label which responses and launches my method fine.
Can anyone say why?
I solved the issue!
I was declaring most variables - as well as the UILabel - in closures blocks, at the top of the class, like below:
let myLabel: UILabel = {
{
let view = UILabel()
view.translatesAutoresizingMaskIntoConstraints = false
view.isUserInteractionEnabled = true
view.textColor = UIColor.blue
return view
}
Within this closure I had view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(doMyLabelMethod(_:)))) and view.isUserInteractionEnabled = true, when I moved them out of the closure and placed them directly above addSubview(myLabel) it fired fine.
So variable-closures are good to contain many dressing, but not gesture recognizers!

Add custom recognizer delay

I've disabled delaysContentTouches in my tableview subclass using:
delaysContentTouches = false
subviews.forEach { ($0 as? UIScrollView)?.delaysContentTouches = false }
But in one of my sections, I still want to keep the delay. Is there a way to cancel the delay for certain sections or perhaps I can add a custom recognizer delay to a section?
Sections are not actual objects within a tableView, so my answer to your first question is no. The .delaysContentTouches applies to the entire tableView.
For your second inquiry, I believe that one way it could be possible is through setting a delay for desired cells' scrollView subview. In your tableView(cellForRowAt: indexPath) func, you could have something like this:
if indexPath.section == 3 { //or whatever your desired section is
for view in cell.subviews {
if view is UIScrollView {
let currentView = view as! UIScrollView
currentView.delaysContentTouches = true
}
}
}
This will find the UIScrollView in your cell's subviews in your desired section. It will then set the .delaysContentTouches property accordingly.
I have not personally executed this code, just researched it, so let me know if it works.
Edit
Apparently the UIScrollView in UITableViewCell has been deprecated, so the above method will not work anymore.
My next best suggestion to you is to use a UILongPressGuestureRecognizer. This will not be quite the same thing as delaying the touch, but could have a similar effect in real execution.
You could use it in the same tableView(cellForRowAt: indexPath) func as so:
let press = UILongPressGestureRecognizer(target: self, action: #selector(handlePress))
press.minimumPressDuration = 2.0 //however long you want
cell.addGestureRecognizer(press)
Whatever you are trying to achieve by selecting certain rows of your tableView could be placed in the handlePress func above which would be trigged upon the long press.

How can i make several labels clickable in a shortcut?

in my code i have a tableView and several labels..
I want that the when the user click on cell and after that click on one of the labels, the text in the label will be same as the text in the row that be clicked.
Q1. How can i enable all labels to be clickable and connect to one function that will point on the specific label each time the user click on it?
Q2. I tried to make the same gesture to all labels with UITapGestureRecognizer.. apparently this gesture refers only to the last label (Lbl4 down here in code example).. it means that the text in Lbl1 in my func change only by clicking on Lbl4.. why is that? and how can i change it that it will refers to all labels?
override func viewDidLoad() {
super.viewDidLoad()
let aSelector : Selector = #selector(ViewController.lblTapped)
let tapGesture = UITapGestureRecognizer(target: self, action: aSelector)
tapGesture.numberOfTapsRequired = 1
Lbl1.addGestureRecognizer(tapGesture)
Lbl2.addGestureRecognizer(tapGesture)
Lbl3.addGestureRecognizer(tapGesture)
Lbl4.addGestureRecognizer(tapGesture)
}
func lblTapped(){
Lbl1.text = self.currentPlayerChooseInRow
}
Thanks for advance...
Firstly, you need to understand UITableView object. UITableView is an array of cells, ok? Then, you need use some methods associated to UITableView like numberOfRowsInSection (where app knows the number of cells) and cellForRowAtIndexPath (where app knows cell will be)
About your questions, i recomend you to use outlets to connect labels, buttons, objects to the controller (try to not use gestures if it is not necessary)
Finally, object cells are programmed into cell. If you have a complex cell, you will need a custom cell controller.