Collection view not scrolling when interacting on a cell - ios

My collection view controller is not responding when swiping on a cell(touch begin in a point on the cell). But it interacts when swipe began a point such as spaces between the cells.
It was previously scrolling vertically, not touch gestures(there was once but i deleted it and nothing really changed) and recognizers in collection view and cell. The interesting part is collection view's didSelectCellAtRow works perfectly fine when interact on cell but not responsive to scrolls.
You can only scroll when swiping from the spaces between the cells or any point in collection view that is not containing cell.
Any thoughts?

Are you sure the touch-down event is passed to the table view (scroll view) correctly?
Make sure the cells don't have a custom touch-down event (e.g. tap gesture recognizer, or touchesBegan method without calling the super inside) and also make sure the collection view delays content touches, it's a common mistake to uncheck it and forget it, and then try to understand why a view is not handling touches properly, but its children are.

Related

UIKit collection view, strange behavior (accessing/scrolling cells)

So I recently implemented a collection view in my app, and I got a bug that I can't seem to solve, searched it and saw no threads about it.
If I have my cursor/finger over the cells i can't scroll through my collection view i need select a "empty" area to scroll.
Second strange Behavior I came across is that I can't directly touch a cell. I need some sort of swipe gesture over it to trigger the code when a cell is selected.
If I go to my collection view on my storyboard and select Delays Content Touches and Cancellable Content Touches in the scrollview section, the collection view scrolls just fine but if I put my finger/cursor over a cell with these option enabled I can't access any cells anymore.
This completely confuses me.
and thank you for reading/considering this thread.
Let's see what your two properties do.
delaysContentTouches: If the value of this property is true, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is false , the scroll view immediately calls touchesShouldBegin(_:with:in:). The default value is true.
canCancelContentTouches: If the value of this property is true and a view in the content has begun tracking a finger touching it, and if the user drags the finger enough to initiate a scroll, the view receives a touchesCancelled(_:with:) message and the scroll view handles the touch as a scroll. If the value of this property is false, the scroll view does not scroll regardless of finger movement once the content view starts tracking.
First, you set delaysContentTouches to false. So the scrollview immediately calls the content view's touch handling methods, allowing it to handle the touch. Obviously, the scroll view won't start scrolling right away because of this, even if you drag.
Second, you also set canCancelContentTouches to false. But if the scroll view isn't allowed to "take over" touches that the content already handles (by cancelling them), it is never able to start scrolling later on either. So if your touch hits a content view, there is no possible way for the scroll view to start scrolling: it isn't allowed to scroll right away because it isn't allowed to delay the content touches, and it can't start scrolling later because it can't cancel the content touches.
I don't know what happens within your cells, not sure what code you put in there. However, you should probably allow your tableview to both delay touches (that means that your cell won't handle swipes that are cancelled immediately anyway because they were intended to be scroll gestures), and to cancel content touches (that means that when you touch down and don't release, you can still start a scroll gesture after a cell became highlighted).
i had the same problem when touching a cell, the problem was that I'm using more than one UIGesture without adding ".cancelsTouchesInView = false" for each one
so if you're using a UIGesture just add Your_Gesture.cancelsTouchesInView = false
and you should be able to access your cells

Make a UIView receive taps but pass swipes to the underlying view

I've got a UITableView and a big "button" view in front of it. The "button" view, which has transparent areas, should be able to response to a tap. But enabling user interaction for this view blocks any scrolling touches from getting to the table view located under the "button" view.
The upper view is a UIView (not UIButton). Given how the two views work together, the upper view is essentially part of what's going on with the table view and reacts to the table view being scrolled. But scrolling is the main thing and I'd like the user to have the largest scrolling area possible.
How do I best resolve this conflict so that the table view is scrollable as usual?
I guess you could subclass your UIButton and UITableView common superview, and override its hitTest:withEvent: to verify which view is hit, something like if you are in a clear or an opaque part of the button?
As pbush25 is mentionning however, it goes more or less against Apple's recommendation.

UIScrollView inside UIScrollView – ignore scroll view touches when in bounds of text view?

I have one UIScrollView inside another UIScrollView, both scrolling vertically. I’m having an issue where when I try to scroll the inner scroll view, the touches are also picked up just afterwards by the outer scroll view. I need touches in the inner scroll view to be exclusively handled by it, and for scrollViewDidScroll to NOT be called on the parent scroll view.
I’ve tried all manner of things, subclassing the scroll view and overriding hitTest:withEvent, setting canCancelContentTouches, setting exclusiveTouch, nothing work at all. The scrollViewDidScroll methods are fired first on the inner one, then on the outer one.
How can I effectively kill the touch after the first scroll view, and not pass it up the responder chain to the outer scroll view?
(FYI: The hierarchy is that there’s a child view controller inbetween, so the outer scroll view contains a child view controller, which in turn contains the inner scroll view).
Apple definitely DOES NOT discourage UIScrollView inside UIScrollView. It's actually in the doc:
your application does not need to do anything to support nesting scrolling. It is supported and provided by default.
https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/UIScrollView_pg/NestedScrollViews/NestedScrollViews.html
If you want to disable the parent scroll view from scrolling, you can probably send a notification from the child, and set isScrollEnabled in parent.

Gesture Recognizer on sub-view outside view's bounds

I'm not sure if this is possible, but I have a view that is able to be dragged around the screen via pan gestures. Once the view is selected, little grippers appear on the corners of the view that allow the user to resize the view. The problem is, those grippers go outside the bounds of the view (they still show up, because clipSubviews is off), but gesture recognizers on those grippers are not firing when selecting the part of them that is drawn outside of the view. Making the view bigger to actually hold the grippers would break a lot of already created logic that is based on the size of the view, so that is a last resort for me.
Is there any other way to get gesture recognizers to work on views that are drawn outside of their parent view?
You could try overriding hitTest:withEvent: in a UIView subclass, and return the gripper view.

ios move touch event between two uiscrollview

I'm building an iOS layout which consists of a UITableView and a UIScrollView. The UIScrollView is inside a table cell of the UITableView and can be scrolled both horizontally and vertically. The diagram below shows this situation. If the user begins scrolling down/up on the UIScrollView the scrolling event should trigger setContentOffset of the table view, and not setContentOffset for the scroll view while the top of the scroll view will be on the dotted line (it's constant height). Then a scrolling touch event should trigger setContentOffset for the scroll view, not for the table view.
In another case: When the user starts scrolling on the table view, it should trigger setContentOffset for the table view, until the scroll view reaches the dotted line. Then the scroll view should handle setContentOffset.
My problem is how to transfer touch events between the table view and the scroll view during one sliding action.
This sounds like one of those cases where you want something quite specific and custom. So trying to do something clever with the gesture recognizers won't be enough.
The main problem is that the ways you can control gesture recognizers such as with gestureRecognizer:shouldReceiveTouch: and gestureRecognizerShouldBegin: only affect the start of the gesture (or for new touches, not ongoing ones), but you want a single ongoing gesture to transition between controlling each view. So for this reason I think you will need to place a large transparent view over your entire screen with a pan gesture recognizer on it and in your handlePan method decide which view you want to adjust and then call setContentOffset directly on that view. You can use the translation of the pan recognizer and the existing content offset to calculate the new one. I know this isn't very elegant, but I can't think of another way to achieve the effect you want.
I'm not sure if this is going to work, but you could try doing something like this:
Option
self.scrollView.panGestureRecognizer = self.tableView.panGestureRecognizer;
Option
[self.scrollView addGestureRecognizer:self.tableView.panGestureRecognizer];
Option
[self.tableView.panGestureRecognizer requireGestureRecognizerToFail:self.scrollView.panGestureRecognizer];

Resources