Horizontal scroll in collection view - ios

I wish to do something when my collection view cell is scrolled horizontally. But I do not know which function gets called when it is getting scrolled.
I have a collection view cell inside of a table view cell, and the collection view cell scrolls horizontally

If you use storyboard, in Attributed Inspector you will find an option that Scroll Direction, make it Horizontal, default this is set to Vertical
programitically
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)

There are several methods that will notify you when a collection view gets scrolled, all of them are contained in UIScrollViewDelegate, and thus in UICollectionViewDelegate protocol, which inherits from the former.
scrollViewDidScroll(_:) is indeed called each time the content offset changes. That means not only the active scrolling issued by the user, but also scrolling by inertia, programmatic scrolling and bouncing. You can use this method to react to the scrolling distance, for example, by querying the contentOffset property of the scroll view.
scrollViewWillBeginDragging(_:) is, in contrast, getting called only at the beginning of scrolling issued by the user (that's why in the documentation you can see that this method may be called only after some delay, since the scroll view's gesture recognizer needs time to decide if it's a tap or a pan gesture). It will not be called again until the user lifts their finger and starts scrolling again.
scrollViewWillBeginDecelerating(_:) is called when the user-issued scrolling discussed above ends, but the scroll view will continue scrolling further to achieve this inertia feeling. Again, it will not get called again until the user lifts their finger one more time.
That's basically it. If this still doesn't narrow down the event that you want to track (for example, you want to become notified when the user starts scrolling at the initial position only), you will need to set some flags or track additional properties.
To track horizontal scrolling for instance, you will need to either compare the scroll view's previous content offset to the current or check the scrolling velocity via scrollView.panGestureRecognizer.velocity(in: collectionView).

First, set your collectionview's delegate to your viewcontroller (or view)
Implement UIScrollViewDelegate methods inside your viewcontroller and you can track your collectionview's scrolling.

Related

Trouble handling interactive state for my UIView

I'll start with my view hierarchy:
ParentView -----> TopBarView (UIView) and CollectionView (UICollectionView)
Scenario:
1) My TopBarView is pinned to the top of ParentView with a height constraint. It is set to handle tap and long-press gestures. Also, my TopBarView's width is equal to that of CollectionView
2) My CollectionView is pinned to the top of the ParentView too! And it has a top padding equal to that of the TopBarView's height. So visually, CollectionView's content starts right below the TopBarView. Also, whenever the CollectionView is scrolled, my TopBarView's constraint is adjusted based on my CollectionView's offset, to visually make it look like it's scrolling along and the inverse is what I'm working on...
My requirement:
I'm trying to make the TopBarView scrollable, so that the CollectionView scrolls along with it too
What I've tried:
To establish scroll behaviour, I'm simply setting the isUserInteractionEnabled property of TopBarView to false, so that the touch events get passed to the underlying CollectionView, and it works as intended!
The Problem:
Since I already support tap gestures and long-press gestures for my TopBarView, I cannot permanently set it to be irresponsive. I have to toggle between the gestures that the user performs i.e: To accept interactions where the user taps or long-presses the view, but deny interactions when user tries to scroll the view(so that the touch events get passed to CollectionView)
All of the above is mostly just for the context. Here's my problem put simply:
My view should respond to taps and long-presses. But when scrolled, it should quit responding and pass the scroll to underlying collection view.
There's got to be something probably trivial that I'm missing out on, and I'm here. TYIA!

UITableview scroll whole cell height

Is it possible to let UITableview move up/down whole cell height just like date picker (not stop between the cell top and bottom)?
The class UITableView is a subclass of UIScrollView.
This means that, if the object you specified as your table view's delegate also adopts the UIScrollViewDelegate protocol, that protocol's methods will be called on it whenever the relevant scroll events happen on the table view.
You can use that timing to "fix" the table view's scroll offset in just the right way to simulate the snap-to-row-bnoundary behaviour you're after.
Some examples:
scrollViewDidEndDragging(_:willDecelerate:): Tells the delegate when dragging ended in the scroll view.
scrollViewDidEndDecelerating(_:): Tells the delegate that the scroll view has ended decelerating the scrolling movement.
Which methods to implement, and what exactly to do in their implementations, will depend on what effect you want to achieve. Play around and see.

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

UICollectionView Cells do not animate movement

When I initiate movement for my collectionView cells, the cells do not move. They move only when I pan my finger over another cell. So if I initiate a movement by pressing one of my cells and then pan, the cells do not track my finger. The only time animation occurs is when my finger pans over another cell. At that point the animation is just the reordering. Bonus: One I end my gesture (lift up my finger) the current cell I was moving around disappears from view. I am using a custom flow layout
My custom flowLayout is stopping the animation. In my custom layout I set the frames of my cells (their attribute frames) to a specific position that is hardcoded in my layout. When the long press gesture is initiated I have to change my attributes somehow.
You don't need to update your attributes. Just make sure you are overriding these methods in your custom layout:
layoutAttributesForElements
layoutAttributesForItem
layoutAttributesForSupplementaryView

Adding a Scrolling Subview to a UITableView (NOT a Cell)

I'm creating my views programmatically. I have a UITableView in my UIViewController subclass that I want to add a scrolling subview to that is not a cell. I want to add some text-based subview to the UITableView that scrolls with the table and starts out above y=0 so the user will only see it if he pushes the table down. That is, it should reside above the first section of my table. If it helps for visualization, I intend to make something similar to those "scroll down to refresh" features and want some indication to the user that scrolling down causes a refresh. Is there any way to do this without something messy like using another UITableViewCell to represent it or abusing the UITableView delegate methods to move a view around whenever the user scrolls?
Simply using [tableView addSubview:] in my viewWillLoad only makes it appear for a split-second then disappear once the table data is loaded. This seems weird to me because UITableView is a subclass of UIScrollView, which is meant to hold other views in it. Using [tableView.backgroundView addSubview] does nothing.
P.S. Why not use a UIRefreshControl for this? I'm still undecided but leaning towards not using one because I don't like how slow that spinning wheel "feels" when the refreshes are usually very very quick. I've been looking at other options like flashing the background subtly and only showing a wheel if it's taking a longer time than usual.
I You can implement pull to refresh with only a table view
To do this using the scroll view delegate, since tableview is a subclass of scroll view.
Set view controller to be the tableview delegate and implement
(void)scrollViewDidScroll:(UIScrollView *)scrollView
When scrollview content offset y value passed a point, add a label to the viewcontroller.view not tableview. When you scroll back or release, remove the view.
You might also be able to add label to the table view and set the frame origin to negative y value, so when you pull the label will move into view (Never tested this do might not work)

Resources