So I have been struggling with this for a while now. I have a UICollectionView that I am using as a menu. The cells are the options to switch to another page. The menu functions exactly how it should except that when you press a cell, say cell 0, it should pop to the next view. What I am finding is that the cell is registering the touch but when I try and determine which cell was pressed is when it falls apart. I have tried debugging it and to me it looks like indexPath has no value! I am using the didSelectItemAtIndexPath function, no it is not didDeselect (I checked that already from my searches on how to fix this). I will post the code but this one has really stumped me. Any help would be greatly appreciated!
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
NSLog("Pressed Cell")
if(indexPath == 0)
{
self.navigationController?.popToViewController(profileViewController, animated: true)
}
}
NSIndexPath comprises both a section and an item, which you can access as indexPath.item and indexPath.section. Assuming you have only one section (so its value is irrelevant), you can change your code to:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
NSLog("Pressed Cell")
if(indexPath.item == 0)
{
self.navigationController?.popToViewController(profileViewController, animated: true)
}
}
I am sure normally call the delegate method but if have add any Gesture to the view. Make sure before you add your gesture recognizers to you're view, make sure the boolean property "cancelTouchesInView" is set to false. This could be because the gesture is recognized so it ignores passing touches to the view causing the cell selection method not to be called. Link to property.
Related
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'm facing a weird issue in UICollectionView using iOS11 emulator. In my project i have a UICollectionView with UIImageView as cells and I've created segue as Triggered Segues for cells by dragging it to a view controller. It was working great but know the segue is not performing so i decided to remove the segue from cells Triggered Segues and I created a segue from my view controller to the destination view controller and performed segue from code
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
if let url = URL(string: "\(StringResources.serverAddress)/Content/images/Files/Thumb/\(photos[indexPath.row])") {
cell.image.downloadFrom(url: url)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("clicked")
performSegue(withIdentifier: "PhotoSegue", sender: collectionView.cellForItem(at: indexPath))
}
but it's not working either and there is no clicked printed in console. I've checked cell and UIImageView user interaction also UICollectionView delegate is ok. How can i fix it?
edit: I've found the problem. It's only calling when I'm double clicking on cell
There are some things that you could check and once all of them are in order it should work:
Check that your UICollectionView has both delegate and dataSource set.
Check that your UIImageView userInteractionEnabled property is set to false.
According to documentation:
Image views ignore user events by default. Normally, you use image views only to present visual content in your interface. If you want an image view to handle user interactions as well, change the value of its isUserInteractionEnabled property to true. After doing that, you can attach gesture recognizers or use any other event handling techniques to respond to touch events or other user-initiated events.
Check that both UICollectionView and parent have. userInteractionEnabled property is set to true.
Check that there are no other UIGestureRecognizers catching your touch event.
Check that there are no network requests freezing your UI.
Considering the information that you provided, I would try to remove the UIImageView from the cell and make sure that the cell touch is working before adding more elements.
the problem is that I was adding a UITapGestureRecognizer to dismiss the keyboard and that was catching touch events.
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
The issue could be due to the fact that collection views have a didSelectItemAt method as well as a didDeselectItemAt method which alternate per click. This could explain why it only works on a double click (one click calls didSelect, the next calls didDeselect).
A quick (but not elegant) solution could be to implement your didDeselectItemAt and just use it to call the didSelectItemAt
I have a UICollectionView and each cell has a UITextView. I'm trying to make it possible to delete the entire cell when long pressing the text in a TextView and selecting Delete from the context menu.
I know I can override Delete by overriding
func delete(_ sender: Any?) {//I want to delete cell from here}
and
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(delete(_:))
{
return true
}
return super.canPerformAction(action, withSender: sender)
}
I just don't know how to find the current cell I am in.
In your func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell set indexPath.row as tag of your UITextView. Then in your func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) or UITextView long press you can access the tag of UITextView which helps to find the current cell.
You can access current cell using this code:
let indexPath = IndexPath(row: textview.tag, section: 0)
let yourCell = self.collectionView.cellForItem(at: indexPath)
I hope this will help you, Or you are experiencing any other problems, let me know :)
Give tag to textfield which should be equal to current indexPath while adding cell to collection view. When long press listener is triggered, check the tag value and based on that, do you operation.
Swift 3 Solution:
So some people were close, but everyone led me down the right path almost. The solution doesn't exactly answer my question, but it could be combined with a gesturerecognizer to answer the question specifically.
So my solution is based on how my code is formatted and may need to be tweaked for anyone else.
First:
From the UICollectionViewCell subclass, where my textview is implemented of course, I overrode the built in delete function. From there is created a variable that is instantiated with with the cells superview, which is a UICollectionView. This allows me to get the indexPath for the cell. From there I also create a variable that is instantiated with the UIView for where my UICollectionView is located. From there I created a function inside my UIView that takes in a IndexPath and deletes the cell.
Inside UICollectionViewCell:
override func delete(_ sender: Any?) {
let cv = self.superview as! UICollectionView
let indexPath = cv.indexPath(for: self)
let view = self.superview?.superview as! UIView
view.delCell(indexPath!)
}
Inside UIView:
func delCell(indexPath: IndexPath) {/*code for cell removal here*/}
func deleteSections(IndexSet)
Deletes the sections at the specified indexes.
func deleteItems(at: [IndexPath])
Deletes the items at the specified index paths
I've got a collection view where I'm dynamically changing between a layout that looks like a UITableView and a layout that looks sort of like the TimeMachine like carousel that I'm calling "SwipeLayout" (which doesn't do swiping right now, but it will eventually).
BTW, The entire project is here: https://github.com/SuperTango/CollectionViewLayoutSwitching. Under the master branch with tag "initial_question"
The initial layout is the table layout, when an item is tapped, I change the layout to the "SwipeLayout" with animation (and back again). In my ViewController, I have:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
NSLog("index Path chosen: \(indexPath)")
changeLayoutTapped(self)
}
#IBAction func changeLayoutTapped(sender: AnyObject) {
if (self.collectionView.collectionViewLayout == tableLayout) {
self.collectionView.setCollectionViewLayout(swipeLayout, animated: true)
self.mode = Mode.Swipe
} else {
self.collectionView.setCollectionViewLayout(tableLayout, animated: true)
self.mode = Mode.Table
}
}
The code for the SwipeLayout is a bit long, so I don't want to put it in this SO question, but here's a link to it: https://github.com/SuperTango/CollectionViewLayoutSwitching/blob/initial_question/CollectionViewLayouts/SwipeLayout.swift
Here's what the transition currently looks like:
For the most part, it looks good. However, if we start the tap on an element other than zero, this happens:
I can't figure out why it goes through the transition and then snaps back to showing the 0 element first.
here's what it looks like after turning on slow transitions in the sim:
I've tried setting the selected element on the collection view like so:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
NSLog("index Path chosen: \(indexPath)")
self.swipeLayout.startingItemIndex = indexPath.item
changeLayoutTapped(self)
}
But no luck there.
Any ideas?
Extra bonus if someone can tell me how to get the contents (the numbers inside) to stay centered in the middle of the view during the entire transition.
Thanks.
I have created a custom UITableViewCell.I have only two rows in my tableView. Now I want to disable 2nd cell when 1st is tapped and disable 1st cell when 2nd is tapped.
How can I do that ? please Help and guide
Implement the UITableViewDelegate method willSelectRowAtIndexPath.
In that method, return the indexPath value that's passed to you if you want the user to be able to select it, or return nil if you don't want it to be selectable.
I'll leave it to you to figure out the logic that decides when different cells should/should not be selectable.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(NSIndexPath(forRow: (indexPath.row + 1) % 2, inSection: 0))?.userInteractionEnabled = false
}