I have a tableview which is populated from core data using an
if let fetchCell = fetchedResultsController...
I'm trying to pass data from all my tableview cells to the gesture recognizer's function so when a cell is swiped over, the recognizer will recognize it and send the variables over to the gesture recognizer's function so that I can work with them.
var Swipe = UISwipeGestureRecognizer(target: self, action: Selector("swipes:"))
rightSwipe.direction = .Right
cell.addGestureRecognizer(Swipe)
The above is simply adding the gesture recognizer to each individual cell.
func swipes(sender:UISwipeGestureRecognizer) {
println("You just swiped the following: \(correct_string)")
}
The above is the actual function of what to do when a cell is swiped. How can I get a variable which was assigned to an individual cell in the if let to print inside the swipes function
Thank you. Hope I didn't confuse anyone.
Rather than using a separate gesture recogniser for each cell (which will, unless you're careful, cause problems with cell reuse), I would proceed as follows:
Create a single gesture recogniser and add it to the tableView.
When the gesture is recognised, in your swipes function, use the sender's locationInView(tableView) to identify the point where the swipe occurred.
Then use the tableView indexPathForRowAtPoint to determine the indexPath for the cell where the touch occurred.
Finally, use the fetchedResultsController's objectAtIndexPath function to obtain the relevant NSManagedObject.
(Presumably correct_string is an attribute of the NSManagedObject.)
Related
An application I'm working on requires a layout very similar to that of the Photos app on iPad. There's a grid of UIViews and the user should be able to pinch into a single one, and as they're pinching in, watch that view grow in size until it's full screen.
So far, I have set up a UICollectionViewController and a custom collection view cell. I added the pinch gesture recognizer to the custom cell. When the user pinches in, the cell grows in size.
The issue I am now having is that the cell isn't layering on top of all other cells as it expands. Rather, it is hiding under the cells loaded after it.
I was thinking that the solution may be that when the collection view controller recognizes the pinch gesture, it could hide the cell being pinched on. Then, create a new UIView that is a copy of the collection view cell, with the bounds equivalent to where the cell was placed. Then, this view can be the one that can be pinched, rotated, and panned. As soon as the user ends the gesture, the view would just animate back to the original cell position and then be set to nil.
However, I'm not sure if this is the optimal solution and maybe there's some easy way to ensure a certain cell is layered on top of all other cells in the collection view.
The code for a snippet of my current implementation of how I'm scaling the cell is shown below. This is the one that creates the issue of the cell hiding under later cells as it expands.
#objc func scalePiece(_ gestureRecognizer : UIPinchGestureRecognizer) {
guard gestureRecognizer.view != nil else { return
if gestureRecognizer.state == .began ||
gestureRecognizer.state == .changed {
gestureRecognizer.view?.transform = (gestureRecognizer.view?.transform.scaledBy(x: gestureRecognizer.scale, y: gestureRecognizer.scale))!
gestureRecognizer.scale = 1.0
}
}
One dirt-simple possibility to remedy the cell being behind others is to invoke bringSubviewToFront(_:) on the collection view, passing the cell.
Caveat however, I'm not sure that this is optimal: since you don't really own the cells/the collection view's hierarchy, generally speaking you shouldn't touch the subviews directly like this.
A closely-related possibility -- not as simple, but probably much more robust and thus preferable -- is to customize the layout. Since the collection view's UICollectionViewLayout object can specify the zIndex of a particular cell, you could reload the cell when the pinch gesture begins and update the Z index for just that cell.
I'm developing an iOS app with a UITableView that requires a swipe gesture to perform a certain action for any cell (row) in the table.
When I initially implemented the IBAction for the gesture in my view controller (the one with the UITableView in it), I wasn't even able to run the app, as Xcode informed me with an error that it doesn't allow attaching gestures to repeating interface elements (the cell being a repeating element, since a new one is generated each time one is needed via dequeueing a reusable cell).
So I then proceeded to place the IBAction for the swipe gesture inside my custom table cell class instead, at which point I no longer receive the error that prevents me from building/running, but am still receiving a warning in the debug console while running the app, which states that since iOS9, the system now enforces the prohibition of gestures attached to repeating elements (in this case, my table cell).
If anyone has insight into gesture recognizers, I'd appreciate it if you could help me figure out the following questions.
Should I take this warning at face value and assume that I'm not allowed to attach any gestures to table cells at all?
In either case, is there some other way to attach a gesture to repeating elements like prototype table cells and avoid any kind of warnings/prohibitions?
You should put the swipe in your viewcontroller and get a cell through Swipe IBAction with the code below. Once you've done that, you can do what you want: cell.do_something or cell.element.do_something
You get the cell with the position of swipe, like:
Objective C:
CGPoint location = [sender locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
Swift:
let location : CGPoint = sender.locationInView(self.tableView)
let indexPath : NSIndexPath = tableView.indexPathForRowAtPoint(location)
let cell : UITableViewCell = tableView(tableView, cellForRowAtIndexPath: indexPath)
Each cell has UITableViewCellReorderControl if canMove return YES value. Possible to create my event and cause, for example via the UILongPressGestureRecognizer to get the cell to start reordering in the table?
Checkout this link :
https://github.com/moayes/UDo/tree/master
1.Add a long press gesture recognizer on the table view.
2.Create a snapshot of the cell when the cell is dragged.
3.As the cell is dragged, move the snapshot around, and call the -[UITableView moveRowAtIndexPath:toIndexPath:].
4.When the gesture ends, hide the cell snapshot.
I want to build a UICollectionView, or use something similar library to make grid view, in which i can rearrange cells. My app supports iOS 7, and, unfortunately UICollectionView method - (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath
is only available on iOS 9 and later.
Is there any way i can achieve the effect of 'drag and reorder' collection view cells on iOS7? Thanks.
Well, I happened to come across the very same issue, so let me add my two cents on this.
In order to achieve to get the same effect of what UIKit does when rearranging cells, I followed a more or less similar approach described below:
Add a long-press gesture recognizer into collection view so that
you’d be able to detect which cell was tapped without messing up
with collectionView:didSelectItemAtIndexPath method.
When user long-presses on a cell, take a screenshot of that cell, add the snapshot view into collection view and then hide the cell. As the user moves his finger on the screen, update the snapshot’s center to move it programmatically so it will look like the user is dragging the cell.
The trick is to decide when and how to swap cells. As the snapshot moves around, it will intersect with other cells. When it happens, you should update your data source and call moveItemAtIndexPath so it will swap the positions of original cell and the cell which the snapshot intersects.
When dragging ends, remove the snapshot from collection view and show the original cell.
You can map those steps to gesture recognizer’s states, so that we know what you should do at each state:
Began: 1
Changed: 2, 3
Ended, Cancelled, Failed: 4
I put an example project in my github account, so you can download and play around with it. Here, I will just implement the gesture callback:
Note: The below code may not work because I threw away some implementation specific details. But it should show the basic intent. Please download the full code from my github repo.
func longPressRecognized(recognizer: UILongPressGestureRecognizer) {
let location = recognizer.locationInView(collectionView)
let indexPath = collectionView.indexPathForItemAtPoint(location)
switch recognizer.state {
case .Began:
let cell = collectionView.cellForRowAtIndexPath(indexPath)
let snapshotView = cell.snapshotViewAfterScreenUpdates(true)
snapshot.center = cell.center
collectionView.addSubview(snapshotView)
cell.contentView.alpha = 0.0 // hides original cell
case .Changed:
snapshotView.center = location // will follow user's finger.
dataSource.swap(originalCellIndexPath.item, indexPath.item) // swaps data
collectionView.moveItemAtIndexPath(originalCellIndexPath, toIndexPath: indexPath) // swaps cells
originalCellIndexPath = indexPath
default:
let cell = cellForRowAtIndexPath(originalCellIndexPath)
cell.contentView.alpha = 1.0
snapshotView.removeFromSuperview()
}
}
Here is the effect you will get (recorded on iOS 8.4 Simulator):
I have designed a UITableViewCell in a .xib. The cell contains an UIImageView that only partially covers the cell. The behavior I am seeking is, if the user taps on the UIImageView, the UIImageView's UITapGestureRecognizer's selector gets triggered, and the UITableViewCell does not trigger didSelectRowAtIndexPath. If the user taps on the UITableViewCell but not the UIImageView, then I want the opposite behavior. Right know what I'm getting is, when the user taps on the UIImageView, both the UITapGestureRecognizer's selector and didSelectRowAtIndexPath get triggered. And when the user taps on just the UITableViewCell, everything works fine. How can I get the desired behavior? I have tried messing around with cancelsTouchesInView among other things.
You don't need to use gesture recognizer to the cell, instead allow userInteractionEnabled set to true for the imageView and add target to the imageView. Refer to this code:
yourImageView.userInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: "imageTapped")
yourImageView.addGestureRecognizer(tapGesture)