UICollectionView subview pan move without scrolling - ios

I have a view that's a collection view subview. And If I pan on that view I would like to move that view. But what happens is that collection view scrolls a bit until I turn scrolling off in gesture begin event. So I've tried no just skip the touch event for collection view pan like that:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if gestureRecognizer == collectionView!.panGestureRecognizer && item.frame.contains(touch.location(in: self.collectionView!)) == true {
return false
}
return true
}
But the problem still persists, collection view still scrolls..

UICollectoinView is a subclass of UIScrollView, try exploring posts that address multi gestures on a UIScrollView, you can start here:
ScrollView gesture recognizer eating all touch events

Okay, so ended up doing like so (not sure if it's the best answer, but at least it works) :
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGesture = gestureRecognizer as? UIPanGestureRecognizer, let otherPanGesture = otherGestureRecognizer as? UIPanGestureRecognizer {
if panGesture == self.collectionView?.panGestureRecognizer && item.frame.contains(otherPanGesture.location(in: self.collectionView!)) == true ||
otherPanGesture == self.collectionView?.panGestureRecognizer && item.frame.contains(panGesture.location(in: self.collectionView!)) == true {
return false
}
return true
}
}

Related

UITapGestureRecognizer not working on top points on UIView

I'm using a UIView with a UITapGestureRecognizer.
On the other hand I have a tap recognizer on ViewController's container view,
Now when i tap on my inner view, it calls handler,
BUT when I tap on for example 40 upper points of it, it doesn't work and container's tap recognizer fires!!!, actually i'm sure it's inside the UIView, i'm sure as I changed it's background to a different color, and on the other hand, there isn't any other views on this view, too!
It's really annoying, i've tested everything, hiding all views, disabling other recognizers and so on! And it's not my first time using this U I TAP RECOGNIZER :///
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(viewController.dismissKeyboard(_:))))
viewWrite.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(viewController.viewPressed(_:))))
EDIT::
I found that even when i touch here on my UITextView, the main container's tap event loads!! but other points of view, no! ::
You can try implementing UIGestureRecognizerDelegate
eg.
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if (gestureRecognizer == recoginiser1 && wrongview1) return false
if (gestureRecognizer == recoginiser2 && wrongview2) return false
else return true;
}
wrongview means something like this.
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if (gestureRecognizer == recognizer1){
let point = touch.locationInView(self.view)
if CGRectContainsPoint(textView.frame, point) == true {
return false
}
}
return true
}

Single Tap Gesture not working on sub view that was added programatically

Background:
I used to have a touch gesture detector on a view, and it worked fine.
Then my app grew, and now I need to add that same gesture detector to 3 views.
The Problem:
The gesture detector is never called when I add it to a views, that have been attached to a parent view with ".addSubview"
The Code:
parentView.addSubview(waveview)
parentView.addSubview(waveviewCap)
parentView.addSubview(waveviewCapBG)
let singleFingerDTap:UITapGestureRecognizer=UITapGestureRecognizer.init(target: self, action: "handleWaveviewTap")
singleFingerDTap.numberOfTapsRequired = 1;
self.waveview!.addGestureRecognizer(singleFingerDTap)
self.waveviewCap!.addGestureRecognizer(singleFingerDTap)
self.waveviewCapBG!.addGestureRecognizer(singleFingerDTap)
Please add UIGestureRecognizerDelegate in your parent view.And update the "shouldReceiveTouch" delegate method.
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view == waveview || touch.view == waveviewCap || touch.view == waveviewCapBG {
return true
}
return false
}
Hope its working...

disabling swiping on uipageviewcontroller for certain area of screen

I have a uipageviewcontroller and the pages have an area on the screen where there is a uitableview. I want the user to only be able to swipe through pages outside of that uitableview.
I can't seem to find where these gesture recognizers are hiding. I am setting them up as delegates like this:
self.view.gestureRecognizers = self.pageViewController?.gestureRecognizers
for gesture in self.view.gestureRecognizers!{
// get the good one, i discover there are 2
if(gesture is UIPanGestureRecognizer)
{
println("ispan")
// replace delegate by yours (Do not forget to implement the gesture protocol)
(gesture as! UIPanGestureRecognizer).delegate = self
}
}
I am seeing ispan in the logs so it seems to find some uipangesturerecognizer but when I override the function like this:
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
println("gesture should begin")
var point = gestureRecognizer.locationInView(self.view)
return true
}
it doesn't print out "gesture should begin" at all... I have the class set as a UIGestureRecognizerDelegate what am I doing wrong? I'm guessing I have the wrong gesture recognizers set as delegates how can I set the correct ones as delegates?
Could something like this work?
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if(touch.view == <your tableView>){
return false
}else{
return true
}
}
You might need to also test which gestureRecognizer it is (the one from the pageView or the one from the tableView).

Pan Gesture in UICollectionViewCell AND UICollectionView

I have a collection view of bars that can slide up and down. Each cell in the collection view is using a UIPanGestureRecognizer to control the blue bar sliding up and down. The collection view does not scroll here.
There is an "edit mode" which disables the pan gesture controlling the bars. The hope here is that in "edit mode", the collection view can then scroll left and right.
My attempt at doing this was to disabled the pan gesture in each of the cells. I also tried using the UIGestureRecognizerDelegate methods to try to disable touches and fail the cell's pan gesture in favor of the collection view's pan gesture. It seems that the collection view's pan gesture is not forwarded to any of the cell's gesture delegate calls.
These delegate calls got me the closest (delegate for cell's pan gesture):
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
return !self.editMode // bar doesn't need to pan in edit mode
}
With this implemented, I could pan the collection view if I started the pan in the white space between cells. Starting a pan on a cell would not do anything, though.
EDIT: I uploaded a sample project of the issue to github.
If I understand this correctly, I think the problem could be as follows:
Your UICollectionView will listen for pan gestures. So far so good.
In KBHBarSlider you add UIPanGestureRecognizer for you sliders. They have "priority" over the underlaying UICollectionView.
This actually makes sense as your BarSliders are above the CollectionView. My best take would be to let the BarSliders add the UIPanGestureRecognizer when needed, and have them completely removed when editing.
So first try and remove the gestureRecognizer you added in VOLBarSliderCell.
Then in KBHBarSlider add something like: (and make sure your init calls addPanRecognizer() instead of setup())
func addPanRecognizer() {
let panGesture = UIPanGestureRecognizer(target: self, action: "viewDidPan:")
self.gestureRecognizers = [panGesture]
}
func removePanRecognizer() {
self.gestureRecognizers = []
}
It is now possible to add and remove the gestures on demand, do so from your edit get/set overrides in VOLBarSliderCell:
var editing: Bool = false {
didSet {
if !self.editing {
self.barSlider.addPanRecognizer()
// Removed code, to keep this example short...
} else {
self.barSlider.removePanRecognizer()
// Removed code, to keep this example short...
}
}
}
Try adding this code at VOLBarSliderCell:29:
self.panGesture.enabled = !self.editing
And remove:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if self.editing && gestureRecognizer == self.panGesture {
return false
}
return true
}
To be fair your problem was not clear to me, so I gave a try as an answer anyway since I cannot comment yet to request clarifications.
I understood you wanna scroll your UICollectionView while you are in edit mode. So that's what the code above does. If you wish to disable scrolling altogether UICollectionView while NOT editing then you can use scrollEnabled = false on the UICollectionView.
Clarify a bit better what is the problem you are trying to solve. That way you might be able to bring precise answers.
You're on the right track. Keep a reference to your leftRight gestureRecognizer. Then in shouldReceiveTouch, check if editing and the gestureRecognizer is your leftRight recognizer
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if(self.editing && gestureRecognizer != self.leftRightRecognizer){
return 0;
}
return 1;
}

Begin drag and drop after long tap

I'm creating a view where its subviews can be re-arranged with drag and drop, after activating the "edition mode" via a long tap.
I use for that two gesture reconizer a UILongPressGestureRecognizer and a UIPanGestureRecognizer.
Everything works great, but i wanna be able to start dragging my subviews without having to tap again on my view (like when you re-arrange your icon on the springboard).
Is there any way to do such a thing ?
EDIT :
I've tried :
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
var res = false
if ((gestureRecognizer == longTapGesture && otherGestureRecognizer == panGesture) || (gestureRecognizer == panGesture && otherGestureRecognizer == panGesture)) {
res = true
println("🐷")
}
return true
}
without success.
First of all those 2 gesture recognizers should work nicely together. Normally one of them would cancel the other one. To prevent that you can use UIGestureRecognizerDelegate method gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer: and return YES for both recognizers.
After that you need to have a boolean property to lock your pan effect before long press occurs. UILongPressGestureRecognizer target method should only perform something if this property is set to YES. Remember to set this property to NO, when pan gesture finishes/resets.

Resources