I have a UICollectionViewController and each of my UICollectionViewCells contains a subview WKWebView. I am trying to implement the installsStandardGestureForInteractiveMovement = true so I can re-order the cells. I have implemented the
collectionView(collectionView: UICollectionView,
moveItemAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath)
But it seems the WKWebView is intercepting the long press. How can I fix this so that it is ignored on the WKWebView so re-ording works as expected?
Thanks,
Rob
WKWebView has its own long-press recognizers which can intercept long-press gesture on the cell.
To fix this, you can add into the cell a transparent view covering the web view. If you need to have also interaction on the web view working, you will need to implement collection view re-ordering interaction by yourself with methods:
- beginInteractiveMovementForItemAtIndexPath:
- updateInteractiveMovementTargetPosition:
- endInteractiveMovement
- cancelInteractiveMovement
Related
In my iOS app, I do have my UIScrollView that contains UITableView with classes (cells) containing UIImages.
Now I do need to update the UIImages programmatically.
However the visible part of my UIScrollView does not update, unless I do scroll the changed item (UIImage) off the visible screen and back.
I've tried setNeedsLayout, setNeedsDidsplay for my UIScrollView, UITableView -- no success.
Any idea on what I could do wrong, or how can I force the ScrollView to update without actual scrolling?
Solved.
At first, UITableView inside UIScrollView was unnecessary since UITableView scrolls itself.
The solution was to use ReloadData method for my TableView.
this is because tableView calls func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell when cell reappear on screen so that it can reuse cell object to save memory, so call tableView.reloadData() or func reloadRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) whenever ( after data is changed obviously ) you want to reload the entire tableView or particular cell respectively.
And no need to use scrollView for tableView since tableView inherits from scrollView.
If I am using UICollectionViewController with diffableDataSource and tapping on cell - it highlights, but then gets unhighlighted while I'm still holding finger on it.
If to use UIViewController + collectionView with diffableDataSource - then everything working as intended, and cell keeps highlighted until I release finger from it. The same if to use UICollectionViewController with standard dataSource - everything working good.
Has anyone noticed this problem as well? Any advice or thoughts would be appreciated, maybe I'm just missing something, but for now it feels more like a bug from Apple side
You can see the example here:
https://github.com/ashishbl86/MockAppStore/blob/0ea8e74a4823c8c80bd7e8d5c6a9514958fbe459/MockAppStore/CollectionViewController.swift
Just add to CollectionViewController.swift file these methods:
override func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
print("cell highlighted")
}
override func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
print("cell unhighlighted")
}
and you'll see that "cell unhighlighted" is printed while your finger is still on a cell
okay as it turned out we need to set
installsStandardGestureForInteractiveMovement = false
this variable installs a standard gesture recogniser for UICollectionViewController to drive the reordering process.
It is set to true by default, but in order to make things work the collectionView dataSource must declare its support for reordering items by implementing the appropriate methods.
In old good dataSource methods moveItemAt are marked as optional, while in diffableDataSource it is not declared as optional any more, which is the reason for this variable to cause the behaviour described in the issue above.
More info about this variable available in docs:
https://developer.apple.com/documentation/uikit/uicollectionviewcontroller/1623979-installsstandardgestureforintera
I have a collection view controller. One of collection view's cells contains a button with Touch Down and Touch Up Inside.
Strictly speaking, the button is in the view of view controller which is a subview of the collection view cell.
When the button is pressed the Touch Down is fired and when the button is released the Touch Up Inside is fired. Until the button is not released the button is grayed and the Touch Up Inside is not fired.
This is exactly the behaviour I need.
Now, I have implemented these two methods to support reordering collection view's cells:
func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
If the second method is implemented (both if canMoveItemAt returns true or false), the button behavior changes:
as soon as the button is pressed, fires the Touch Down event and immediately after that, it also fires the Touch Up Inside event.
the button is grayed when pressed and immediately gets back to its normal state like it has been released
when the button is released, nothing happens
My suspect is that events propagate from button to the collection view controller, but I have no idea how to prevent it.
Can anyone help me?
Tks
You are right, but if you stop it, you stop reordering as well. Basically you need to choose what do you need: button to be pressed or cell to be dragged. Perhaps you can achive expected behaviour utilising Collection cell capabilities, instead of button. You can easily change button states, if you need button to represent that cell is being dragged.
I want to implement pull to refresh effect but on UITableView bottom using UIRefreshControl ?
Any ideas?
It is not possible to put UIRefreshControll to bottom of UITableView in a manner similar to putting it to top. But anyway, you're able to place everything on table view's background view.
But the solution which I prefer is to download additional items when user scrolls to the most bottom of table view. I handle it via UITableViewControllerDelegate method:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == self.items.count - 1 {
// Download more items
}
}
These are the two things i typically do:
Configure a Footer View which displays the loading Indicator.
Provide a additional cell from the TableViews or CollectionViews
Datasource which presents a loading indicator. Depending on the current loading state it could display a label like "No more items available" or the actual Indicator
I am making an iOS app that relies on a table view. In each cell of the table view, there are 4 buttons aligned on the bottom. I have a cell class that is pretty standard and a feedController to handle the table and setting all the items of the cell.
Everything works fine on it but I can not figure out how to handle the button clicks within the cell. I can hard code it into my cell class, but then every 3 cells has the same interaction. Is there a way to pass the button click function from the cell class into the controller? I have tried checking the state from the controller and that has not worked.
Can you add a gesture recognizer as you're doing your cellForItemAtIndexPath? So I had something similar with a collection view, and what I did was as it within:
func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell!
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as MyCollectionView
...
I would add a gesture recognizer to each cell
i.e.
cell.addGestureRecognizer(UITapGestureRecognizer(target: self, action:Selector("tapAction:")))
And then something like:
func tapAction(recognizer: UITapGestureRecognizer) {
...
}
so recognizer ends up being the specific item tapped, and I could take action accordingly (in my case, I had my datasource of items and I would find the item in an array by casting recognizer to a cell, finding the appropriate subview, and update values on it)
I would add code block properties to your cell class which the table can assign to deal with each button. In your cell, code each button handler to call the appropriate block, or pass an index for the button used in a single block.
See my answer here which has an example, but for a switch.
How can I get index path of cell on switch change event in section based table view
If after a few cells you get the same interaction, it's possibly because you're dequeueing a reusable cell, and you're getting the same cell.
Make sure to set your .setTarget() call for your buttons in your tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) data source every time the cell is dequeued. It would help if you shared how you're handling dequeuing to see if this is your issue.