I would like to create an app with a list of TODO items. Each TODO should have a functional checkmark/checkbox on the left side of the cell. If I click on the right side of the TODO then I would like to show its details.
I have create a Table View. When I click on a cell I follow a segue to a UIViewController that shows the details of the cell.
I think displaying the checkmark may be possible by defining the cell's imageView. However, I can't make the imageView functional, i.e., clickable. Every time I click on it it simply shows the details.
Can you provide basic sample code to show how I can have both a segue to the details of the cell AND a checkmark that is clickable?
Thanks, Daniel
OK, I figured it out. Added this code snippet:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
//...
let singleTap = UITapGestureRecognizer(target: self, action: Selector("tapped"))
singleTap.numberOfTapsRequired = 1
cell.imageView?.userInteractionEnabled = true
cell.imageView?.addGestureRecognizer(singleTap)
//...
}
func tapped() {
println("tapped!")
}
Related
Based on https://github.com/pgpt10/DragAndDrop-CollectionView
By using
self.collectionView.dragInteractionEnabled = true
self.collectionView.dragDelegate = self
self.collectionView.dropDelegate = self
Once you long press anywhere within a collection view cell, the following function will be triggered
extension DragDropViewController : UICollectionViewDragDelegate
{
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem]
{
let item = collectionView == collectionView1 ? self.items1[indexPath.row] : self.items2[indexPath.row]
let itemProvider = NSItemProvider(object: item as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
However, I have a different requirement.
I have a collection which looks as the following
I wish when user tap (not long press) on the right 3 horizontal lines icon, he can immediately perform drag and reorder. Tapping other region, or long press on the cell, will not have drag and reorder effect.
May I know how can I achieve so?
Some notable app in App Store which able to achieve such feature
I notice Google Keep in App Store, able to achieve such feature. By just tapping on the left most icon in their Todo list, we can immediately reorder the Todo list item.
Wondering how they did that?
Approach 1: Install long press gesture on Cell's reorder icon
I had tried
Install long UILongPressGestureRecognizer on cell's reorder icon.
Use gesture.minimumPressDuration = 0 to mimic tap behavior.
class TabInfoSettingsItemCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
...
let gesture = UILongPressGestureRecognizer(target:self, action: #selector(longPressGesture))
gesture.minimumPressDuration = 0
reorderImageView.addGestureRecognizer(gesture)
}
But the outcome isn't encouraging. The "move" action isn't working at all!
Complete code can be found here : https://github.com/yccheok/ios-tutorial/tree/gesture-on-cell/TabDemo
Approach 2: Install long press gesture on Collection View
I had tried
Install long UILongPressGestureRecognizer on Collection View
Use gesture.minimumPressDuration = 0 to mimic tap behavior.
Here's the code snippet
let gesture = UILongPressGestureRecognizer(target:self, action: #selector(longPressGesture))
// Mimic short tap. But this blocks the events for delete button and text field :-(
gesture.minimumPressDuration = 0
collectionView.addGestureRecognizer(gesture)
But the outcome isn't perfect.
How can we recognise the tap event only within the reorder icon (icon with 3 horizontal lines) boundary.
Delete button no longer work as UILongPressGestureRecognizer blocks it from receiving event.
Text field no longer work as UILongPressGestureRecognizer blocks it from receiving event.
Complete code can be found here : https://github.com/yccheok/ios-tutorial/tree/gesture-on-collection-view/TabDemo
remove UILongPressGestureRecognizer from UICollectionView, Remove gesture comment from TabInfoSettingsItemCell class.
Replace this method in TabInfoSettingsController:
func changed(_ gesture: UILongPressGestureRecognizer) {
print("==changed==")
collectionView?.updateInteractiveMovementTargetPosition(gesture.location(in: collectionView))
}
and try that works.
This question already has answers here:
How to detect tap on clear part of UITableView?
(4 answers)
Closed 3 years ago.
I am currently creating a UITableView with custom cells to allow users to search other users. When the table is filled with data (usernames), it works great. I check if the keyboard is visible when a tap is detected, and if so, I dismiss the keyboard. If the keyboard is not shown, it pushes to the UIViewController containing the user's profile. This is the code to do so:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if(keyboardShowing) {
dismissKeyboard()
return
}
let userVC = UserController()
let navViewController = tabBarController?.selectedViewController as? UINavigationController
userVC.profileUserID = resultUsers[indexPath.row].userID
navViewController?.pushViewController(userVC, animated: true)
}
However, when there is only one row (so the search returns one user, for example), I want to be able to click outside the rows to allow the user to dismiss the keyboard. I tried the following:
let tableBGTap = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
self.userList.backgroundView?.addGestureRecognizer(tableBGTap)
This doesn't work though. Any idea on how I can make it possible to achieve what I want? Long story short: if there are fewer rows in my UITableView to fill the entire screen, I want to be able to tap on the "background" below the rows.
The reason of why
self.userList.backgroundView?.addGestureRecognizer(tableBGTap)
is not working because backgroundView is nil. Therefore, what you should do is:
userList.backgroundView = UIView()
self.userList.backgroundView?.addGestureRecognizer(tableBGTap)
Note That if you are setting a background color for the table view:
userList.backgroundColor = .red
won't be displayed anymore. As a workaround, you could add a color to the background view itself:
userList.backgroundView = UIView()
userList.backgroundView?.backgroundColor = .red
userList.backgroundView?.addGestureRecognizer(tapper)
I have a custom UITableViewCell subclass where I am putting two buttons in the cell, I want both to be clickable, but so far I cannot even get any kind of click to trigger (besides row selection, but I disabled that on my UITableViewController subclass). Basically When one of two buttons is selected, it should remove those two buttons and update what is in the cell with a list of selectable choices (also buttons). I am doing everything programmatically (no IB).
My TableViewCell with Initial Two Buttons
I have looked around a lot and haven't found anything that handles more than ONE button in a tableViewCell. Currently I've been trying to add targets to my buttons in my UITableViewCell's awakeFromNib():
for button in initialChoiceButtons{
button.isUserInteractionEnabled = true
button.addTarget(self, action: #selector(initialChoicePressed(sender:)), for: UIControlEvents.touchUpInside)
}
One thing I've tried is in my tableView in cellForRowAt for my custom cell is to bring my buttons to the front of the cell:
for button in (cell as! FormDropDownTableViewCell).initialChoiceButtons{
cell.bringSubview(toFront: button)
}
I'm really stumped and feel like this should easy. I'm on the verge of just using a stackView inside of scrollview for everything...
Ok so I figured out a somewhat clean way to separate button taps in my tableviewcell, by creating a delegate protocol with a function that I'll call from my target in my tableviewcontroller for every button in my tableviewcell.
protocol UIButtonSelectorDelegate{
func handleTap(button:DelegatingButton) //will select different functions based on DelegatingButton.actionType
}
class DelegatingButton:UIButton{
var selectorDelegate:UIButtonSelectorDelegate?
var actionType:String = "default"
}
in my FormDropDownTableViewCell I conform to the UIButtonSelectedDelegate and implement handleTap like so:
func handleTap(button:DelegatingButton){
switch button.actionType{
case "initialChoiceSelect":
initialChoicePressed(initialChoice:button) //specific method for certain button.actionType also in my FormDropDownTableViewCell
case "cardTypeSelect":
cardTypeSelected(selectedCardType:button)
default:
break
}
}
Now I add the target-actions for every button in cellForRowAt in my tableviewcontroller like so:
button.addTarget(self, action: #selector(handleButtonTaps), for: UIControlEvents.touchUpInside)
and the handleButtonTaps func in the tableviewcontroller is simple:
func handleButtonTaps(sender: DelegatingButton){
sender.selectorDelegate?.handleTap(button: sender)
}
Enjoyed Talking to myself =P ..
I am trying to replicate the same type of functionality as the stock iOS Mail app when a user swipes a tableview cell as currently seen here:
There are 3 options: More, Flag, and Archive. When the user taps on any one of the 3, the background color changes to indicate it's in a highlighted state. However, the icon and text do not change color.
I am trying to achieve the same effect.
I am following this tutorial guide to make a custom swipeable tableview cell using gestures:
How To Make A Swipeable Table View Cell With Actions – Without Going Nuts With Scroll Views
Currently I have this set up:
In each cell contains 3 UIViews, where each UIView contains an UIImageView and UILabel representing Dirty, Edit, Delete.
I am adding tap gestures to the 3 UIViews like so:
let dirtyButtonView = cell.viewWithTag(7)
let editButtonView = cell.viewWithTag(8)
let deleteButtonView = cell.viewWithTag(9)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyVC.buttonPressed))
tapRecognizer.numberOfTapsRequired = 1
dirtyButtonView?.addGestureRecognizer(tapRecognizer)
editButtonView?.addGestureRecognizer(tapRecognizer)
deleteButtonView?.addGestureRecognizer(tapRecognizer)
However, I cannot achieve the highlight state functionality that the Mail app has when a user selects one of the 3 options.
I'm not sure if this is the correct implementation, i.e. having a UIView and adding a gesture to it?
How can I achieve something similar to the iOS Mail app swipe functionality?
Thanks
I found exactly what I was looking for, SwipeCellKit, by jerkoch. This library performs the same exact actions as the stock iOS Mail app does when swiping to the left. No need to deal with different UIViews and UIButtons.
To use, simply conform to the SwipeTableViewCellDelegate, and use it in editActionsForRowAt like so:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
return [deleteAction]
}
Make sure to change the cell's class to SwipeTableViewCell and set its delegate like so: cell.delegate = self.
I would take a look at the SWTableViewCell by CEWendel. It looks like it has exactly what you're looking for.
May be late to answer this, but in case anyone else is looking - consider this read to answer the question: https://www.raywenderlich.com/62435/make-swipeable-table-view-cell-actions-without-going-nuts-scroll-views
I have a prototype cell with an UIImageView, when user tap this ImageView, app should display a Collection View where user can select an alternative icon for the cell. So, in UITableViewCell I added a Gesture Recognizer:
internal let iconTappedGR = UITapGestureRecognizer()
then I implemented it in table's cellForRowAtIndexPath:
cell.iconTappedGR.addTarget(self, action: #selector(changeIcon))
cell.iconView.gestureRecognizers = []
cell.iconView.gestureRecognizers!.append(cell.iconTappedGR)
and I added a changeIcon function
func changeIcon () {
print("imageView tapped!")
}
trouble is that it doesn't works; I tried even using storyboard but is the same...where am I wrong?
I solved using
cell.iconView.userInteractionEnabled = true
following this answer https://stackoverflow.com/a/36495864/2085352 to a question posted 30 minutes later than mine!