How to edit tableview cell on TAP instead of swipe - Swift - ios

I have a UITableViewController and at the moment, the user can swipe left on the cell to reveal an 'add to favourites' button. I would now like to add an icon to the cell that the user can tap to reveal the this button (does the same thing as swiping to the left). This will just act as a visual aid for the users who do not know swiping left will do the same thing.
For my TableView, I use the following code to 'close the cell' when the user has pressed the button:
itemsTableView.setEditing(false, animated: true)
From this I assumed that to manually open the cell I would simply call:
//Get cell
let cell:TableViewCell = itemsTableView.cellForRowAtIndexPath(NSIndexPath(forRow:
sender.tag, inSection: 0)) as! TableViewCell
//Open cell to reveal button
cell.setEditing(true, animated: true)
Unfortunately this does not work. So I would like to know what is the function that is called when a user swipes to the left of a cell and how can I replicate it when a user taps on the icon?

I don't think you're going to be able to do it, sorry. This feature relies on the UITableView's pan gesture recognizer. When the user pans sideways, the table view checks the editActions... delegate method and, if we have edit actions, inserts a private confirmation view behind the cell and allows the cell to be moved to reveal it. You can't trigger that behavior programmatically as far as I can tell.
This would be a reason — one of many very good reasons — for sticking with a third-party scrollable cell class. In this way, the cell is a horizontal scroll view and you just scroll it in code.

Related

Swift - Is it possible to move to the next cell in tableview with the click of a button?

I have a tableview and custom cells which take up the fullscreen however I am wondering if upon click of a button in my cells I could move to the next cell automatically, kind of like how when you scroll more than half in TikTok it automatically goes to the next video. Aside from manually scrolling at a faster speed which is the only way I can think of, is there any other way to automatically move to the next cell, impersonating a full scroll?
Thanks for the help.
You can use that method:
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
Approach 1
Just delegate your tap event (IBAction of the button inside of your custom cell) back to your UIViewController that holds the UITableView reference and call scrollToRow(at:at:animated:).
Approach 2
You could also handle with tableView(_:didSelectRowAt:). Next cell would be the indexPath.row + 1 with scrollToRow(at:at:animated:)

Xcode7.3 UITest of Disclosure Indicator in a custom TableViewCell

(Xcode 7.3.1, iOS9.3, Swift)
I'm struggling with setting up an UI Test in my assignment for what would seem to be a fairly standard and common use case.
I have a sub-classed UITableViewCell which contains a textField that does not fill the entire cell and has the Disclosure Indicator set. The user is able to type the data into textField by tapping on it, but if they tap outside the textField, but still in the cell, my app segues to another view. The project works fine and the child view receives the correct data from the cell's textField.
My Master-Detail app has UITableViews on both the Master and Detail views. My UI Test selects the first cell in the Master View, waits a little for the DV and then selects the second cell in the detail view, which is configured in accordance to my earlier description.
I am simulating a tap on the second cell using
tablesQuery.cells.elementBoundByIndex(1).tap()
However, the simulator interprets it as a tap in the textField, so no segue occurs. I have read SwiftyCruz's question and the given answers but his use case is a little different, as I'm not using a Detail Disclosure, also the accepted answer doesn't translate to my situation. In following ferunandu explanation, I have tried setting the Accessibility Label and Identifier on the Cell as well as a different string for the accessoryView?.accessibilityIdentifier. Though UI Test still doesn't work, ferunandu's snippet does change the disclosure indicator from > to a blue box.
Using a breakpoint, I've been querying the app object in the debug window trying to find the right control, but to no avail. I am able to find the textField using indices as well as the identifier, but nothing I've tried has returned .exists true for the accessoryView.
Am I trying to access the cell incorrectly? Or, is it actually not possible to do what I'm attempting?
The code for my test is:
XCUIDevice.sharedDevice().orientation = .Portrait
let app = XCUIApplication()
wait()
let tablesQuery = app.tables
tablesQuery.cells.elementBoundByIndex(0).tap()
wait()
tablesQuery.cells.elementBoundByIndex(1).tap()
What am I not understanding properly here? Any advice would be greatly appreciated.
(I know I could have used a standard UITableViewCell with the data entry done on the child view, but I prefer not to change the design of my app to accommodate XCTest's, seems a bit backwards.)
I have a sub-classed UITableViewCell which contains a textField that does not fill the entire cell...
I am simulating a tap on the second cell using
tablesQuery.cells.elementBoundByIndex(1).tap()
However, the simulator interprets it as a tap in the textField, so no segue occurs.
It sounds like your tap on the table view cell is being intercepted by the text field. When UI tests tap on a table view cell, the tap will be at the centre of the UI element's frame.
To offset the tap location from the centre of the cell, use coordinate(withNormalizedOffset:) and tap the coordinate instead of the element directly.
let cell = app.tables.cells.elementBoundByIndex(0)
// Retrieves coordinate that is 50% of the way along the cell
// and 20% of the way down the cell - adjust these values to
// find the right values to avoid tapping the text field area
// of the cell
let cellCoordinateForTap = cell.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.2))
cellCoordinateForTap.tap()

Call to didHighlightItemAtIndexPath without a call to didSelectItemAtIndexPath for UICollectionView

I have a UICollectionView where I overrode hitTest:withEvent: in my UICollectionViewCells in order to allow for taps just outside of the cells to register as taps on the cells.
When I do this and I tap just outside the cells that now register as hits, I get calls to didHighlightItemAtIndexPath and didUnhighlightItemAtIndexPath, but I don't get a call to didSelectItemAtIndexPath. If I tap inside the cell I get all of the expected highlight and select item calls as I did before.
I don't have any custom gesture recognizers set up and I don't override touchesBegan or anything like that.
So does anyone know under what conditions you get a call for didHighlightItemAtIndexPath without a call to didSelectItemAtIndexPath? Is there any way to get my didSelectItemAtIndexPath called? Thanks.
EDIT
I forgot to mention that my UICollectionView is within a Today Widget, so it is contained within the Notification Center scroll view. If I move my select code into the didUnhighlightItemAtIndexPath, then it is called when you tap outside the cell, but the result is that you can't actually scroll the Notification Center without selecting one of the cells.
So perhaps the difference between the highlighting and selecting that I'm experiencing here has something to do with the scroll view responder canceling the selection outside of the cell?
OK, I figured out what was going on.
I added a new UITapGestureRecognizer to my UICollectionView. Implementing it like this led me the the solution:
- (void)cellSingleTap:(UITapGestureRecognizer *)sender
{
CGPoint point = [sender locationInView:collectionView_];
NSIndexPath *indexPath = [collectionView_ indexPathForItemAtPoint:point];
[ .... ]
}
When I checked the points returned when I got highlighting but no selection, it became apparent that it happened when the point tapped on was within the section insets of the collection view layout. And when the taps were on the section insets, the indexPathForItemAtPoint calls returned nil.
So basically the collection view will highlight, but not select, taps that are outside cells but are within its section insets. As long as the taps are outside the cells and not within the insets, those taps will result in calls to didSelectItemAtIndexPath.
Since I would like taps within the insets to count as taps on cells, I was able to workaround this issue by adjusting the tap points before my call to indexPathForItemAtPoint.

How can I detect a right swipe on UITableCell and display a custom button instead of Delete button

I want to display a "Duplicate" button where the Delete button would usually appear if the user swipes from left to right on a UITableView cell. I understand I can add a gesture recogniser to the cell as per this example https://stackoverflow.com/a/6167841/2567126.
How do I create and place a button on the cell so that it appears in a similar manner to the Delete button to allow the user to confirm the action? The cells are just standard UITableViewCells with the default style.
You can change the title of delete button with delegate method - tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:.

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.

Resources