Handling gestures for UICollectionView that is embedded in a UIPageView - ios

This question has satisfying answers for the bigger part of this question but there's a small case that I can't get rid of.
After using the method from the accepted answer
Only one of the pages inside the PageView has a CollectionView. When you swipe into that one page and swipe again the collection view handles the gestures because the pageView no longer has a datasource.
If I keep swiping and get to the last cell of the collectionView my next swipe goes to the PageView because I set the datasource (when i was on the last cell). And all is well.
The Problem
Problems start if I change my mind.
On the last cell, if I move my finger slightly towards the next page and then (without removing my finger) swipe towards the previous cell it jumps to the previous page (not the previous cell). Supposedly because the datasource has been set, and the gesture that was supposed to set it to nil was not recognised.
Has anyone had this issue? How do I handle gesture that started in one direction and then went in the other?

Related

Swipe to delete on entire section in UITableView

I have a UITableView which has a variable amount of sections and every section has a variable amount of rows. Every section contains a section header, a section footer and the rows for that section. They are shown and displayed inside a container. Everything up until now works as expected. To demonstrate what my UITableView currently looks like:
I am now trying to implement the possibility to swipe left on the entire section, so that the header of the section, the rows inside this section and the footer of this section move to the left and display another UIView. I am capable of swiping the cells separately, but enabling this feature on the entire sections have caused headaches for the past two days. This is what I would like to achieve:
I have thought about implementing UIGestureRecognizers but I am afraid they might conflict with my UITableView. Also, I started implementing it, but I would not know how to move solely the section on which was swiped to the left.
Then I thought I could maybe implement a UIScrollView as container for each section. How I would accomplish this is still a mystery to me, but it seems like a possible solution if this could be done.
Furthermore I am out of ideas and stuck on how this should be done. It's something I have not found on the Internet so far - at least no working examples of some kind so I have zero inspiration on how to achieve the effect.
I therefor would like to ask if somebody has an idea of how this could work and what I have to keep in mind when implementing this. Every clue pointing me towards a working solution is gratefully appreciated!
EDIT: I have already seen the possible duplicate this afternoon. However, the suggestion there shows touchesBegan() on the header, which does not work in my case as I need the entire section to be "draggable".
I think one way you can implement this is with a vertical stackview containing views that contains a tableview and the trash icon. When a user swipes left on the tableview header, it will show the hidden trash icon in the view. I would think that each tableview only has one section so it will be easier to keep track of which "section" the user has swiped.
I have currently managed to arrange a similar solution. I take the rectangle of the section with rect(forSection:int), add a UIPanGestureRecognizer in which I add a UIView on top of the UITableView if touches began, I calculate the location of the finger and let the cudtom UIView follow. When a certain point (100 from left edge of the UITableView) is reached, the section gets removed with deleteSections(indexSet:with:).
This works. It does the job, but it adds an overlay to the section rather than pushing it to the left.
Therefor I am asking of someone knows if there is any way of setting the offset for one specific section or for an area of a UIView, so I can offset the rectangle of the section. I have been able to setContentOffset on the entire UITableView but this is not the desired result.
If there is no way to do this, I would consider keeping the solution I have now or maybe implement a snapshot feature which takes a screenshot and crops the rect of the frame, adding this UIImage to the custom view to simulate the section. But that would be tricky. Any ideas for this idea are also welcome.

UITableView inside of UIScrollView or using TableView Header

I guess this question is more of a best practice question than a problem solving question.
I would like to have a page on my app that has a UITableView at the bottom of it and some buttons/text above the UITableView but instead of just the UITableView scrolling, I would like the whole page to scroll.
I have been searching around and some people say to put the UITableView inside of a UIScrollView and disable scrolling on it and recalculate the height so the table view is as tall as all of it's rows.
Then I have read some other people say just to put the buttons/text in a Table Row Header and just have that scroll with the whole table view.
Which is the better practice and are either of them frowned upon?
Thanks!
Open the main storyboard and on the bottom right hand side you should see a list of view controllers, buttons, gestures etc.. In that list there should be a controller called "page control" that opts for the page-scroll you are looking for as well as the continuous one which you are trying to get rid of, you can just insertt this in to your basic view controller (via drag and drop). As for the button responsible for the segue (turning the page) you can find that in the list too. I can't explain how to program the button to turn the page step by step as I am typing this on my phone at work right now. If you want I can edit this later in more detail

UICollectionView layout malfunction

I'm building a dictionary app, and one of the features is that you can "drill down" into a definition. You look up a word, there's a word in the definition you don't understand, so you tap that word and the app shows you the definition for that word, if available. This is pretty standard for iOS dictionary apps on the App Store, if anyone's familiar.
One feature is that I am going to have a bar that shows each word as you drill down, so you get a sort of "chain" of words across this horizontal bar. The idea is you can tap on the words in the chain to navigate forwards and backwards through your chain of words.
To represent this chain I am using a UICollectionView, with a subclassed UICollectionViewController. Since it's essentially a "grid" with a single row, this made sense to me. I'm using a storyboard, so I simply embedded my custom controller into the main view, pass events back and forth between the master controller and this custom collection controller. Pretty simple.
Now, let's say the user taps many different words, so you get the "chain" of UICollectionViewCells growing across the bar from left to right until you hit the edge. Since UICollectionView is based on/has a UIScrollView in it, this shouldn't be a problem. My concept is that, if the number of items to be displayed exceeds the width of the view, the CollectionView would expand the contentView and place items off the right edge of the view port, and I could then programmatically scroll the view to show the newly added item.
Here's the code that I use to do this (edited). It's a method that I call in my subclassed UICollectionViewController:
- (void)reloadDataWithAnimation
{
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:model.data.count - 1 inSection:0]
atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
}];
}
This is more or less what I'd normally do with a UITableView: tell it to reload its data after I have changed the model. It didn't quite work at first until I found a question on SO that covered the use of performBatchUpdates, and I had trouble doing the scrollToItemAtIndexPath until I realized it needed to go into the completion block.
Now, here's the funky part: everything works fine before the items fill up the whole view. The first time an item would go beyond the boundaries, the CollectionView places the item below the last item in the row. This looks really strange because the view is only one row tall, so you can kinda half-see the item parked below the last one in the row, mostly obscured. No scrolling occurs.
At this point, if you scroll the CollectionView back and forth, the item reconfigures itself and moves into the correct position. Or, if you add another item, they align correctly and the view scrolls as intended. Successive additions work just fine. However, if you scroll back to the left and then add another item, it briefly appears underneath the last currently visible item in the viewport, then the view scrolls off to the far right and as it scrolls the misplaced item jumps up into its proper position.
Although I began posting this question as I could find nothing on Stack Overflow, in the course of writing my question, the Similar Question sidebar updated and I found similar questions, and eventually an answer.
Similar question: UICollectionView cell layout is out of the collection view's bounds
Apparently this issue is known to Apple.
Here is the solution linked to in the above question: https://stackoverflow.com/a/13389461/700471
The code that Nick Snyder posted solved the problem for me perfectly.
Edit: Additionally, in the end I subclassed UICollectionViewLayout, bypassing FlowLayout, and made my own layout with this tutorial.

UITableView tap and hold + drag and drop

I wanted to find out how to do the following:
I have a UItableView, which enters edit mode when the user taps and holds one of the rows
Once it enters edit mode I need the cell to remain selected and give the effect of popping out, under the users finger.
The user should be able to drag the popped out cell and reposition it to another row, without lifting the finger.
What I already have in place:
I have a long tap gesture recognizer and I set the table into editing in the long tap gesture recognizer selector.
However in order to drag the cell I currently require to raise the finger and re tap to drag the cell , which is not what I want.
Any help would be appreciated.
At current moment there is a workaround (not easy enough): https://stackoverflow.com/a/7501076/326017 .
And I have found code snippet here: https://github.com/FlorianMielke/FMMoveTableView
"FMMoveTable is an UITableView subclass that provides moving rows by simply tap and hold an appropriate row without switching the table to it's edit mode" - from description
The article Reordering a UITableViewCell from any touch point discusses this exact scenario.
Essentially you do the following:
Find the UITableViewCellReorderControl (a private class).
Expand it so it spans the entire cell.
Hide it.
The user will now be able to drag the cell from anywhere.
Another solution, Cookbook: Moving Table View Cells with a Long Press Gesture, achieves the same effect by doing the following:
Add a long press gesture recognizer on the table view.
Create a snapshot of the cell when the cell is dragged.
As the cell is dragged, move the snapshot around, and call the -[UITableView moveRowAtIndexPath:toIndexPath:].
When the gesture ends, hide the cell snapshot.

I need to detect a swipe gesture on my tableView that is within a page control, how can I do this?

Pretty straight forward, I just can't get it to work. What can I do to swipe to delete on my tableView that is within a page control?
Please help!
Edited to remove my original answer regarding the proper UITableViewDataSource methods.
This sounds like a potentially complicated user interface (i.e. if users are expecting swipes to turn a page but if they mis-touch and hit the table view cell just right, they'll get the "delete" button). I'd suggest re-thinking what you are doing.
In any event, to get to the finish line on your app might be to subclass UIPageControl, detect when swipes are happening in the content region and pass that swipe message along to the table view. I suspect you can't just do userInteractionEnabled = NO; on the page control's content view.
F.Y.I.: you should also probably delete the identical & duplicate question you posted a number of hours before the question I'm attempting to answer ( How can I capture a sideways swipe gesture for a tableView that is inside of a pageControl? )

Resources