Adding image or text for UILongPressGestureRecognizer in Swift? - xcode

So, some of my users don't realize they can hold a cell to get an alert pop-up with options. So, I would like to add some kind of image or text or color - something - to let the user know "hey, you can hold this to get more info." Here is my code below. Any thoughts on the best way to do this?
// handles long press for editing or sharing a search
func tableViewCellLongPressed(
sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.Began &&
!tableView.editing {
let cell = sender.view as! UITableViewCell // get cell
if let indexPath = tableView.indexPathForCell(cell) {
displayLongPressOptions(indexPath.row)
}
}
}
// displays the edit/share options
func displayLongPressOptions(row: Int) {
// create UIAlertController for user input
let alertController = UIAlertController(title: "Helpful Stuff",
message: "",
preferredStyle: UIAlertControllerStyle.Alert)
// create Cancel action
let cancelAction = UIAlertAction(title: "Cancel",
style: UIAlertActionStyle.Cancel, handler: nil)
alertController.addAction(cancelAction)
let shareAction = UIAlertAction(title: "Share",
style: UIAlertActionStyle.Default,
handler: {(action) in self.shareSearch(row)})
alertController.addAction(shareAction)
presentViewController(alertController, animated: true,
completion: nil)
}
// callback that returns a configured cell for the given NSIndexPath
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
// get cell
let cell = tableView.dequeueReusableCellWithIdentifier(
"Cell", forIndexPath: indexPath) as UITableViewCell
// set cell label's text to the tag at the specified index
cell.textLabel?.text = model.tagAtIndex(indexPath.row)
// set up long press guesture recognizer
let longPressGestureRecognizer = UILongPressGestureRecognizer(
target: self, action: "tableViewCellLongPressed:")
longPressGestureRecognizer.minimumPressDuration = 0.5
cell.addGestureRecognizer(longPressGestureRecognizer)
return cell
}

If you want to use the Storyboard, that may be easier to hook up the gesture recognizer and link that to the button in the Storyboard, instead of having it in the cellForRowAtIndexPath, which is called many times

Related

How to store a hidden string with a UITableViewCell?

I want to attach information (a string) to each UITableViewCell when populating TableView with UITableViewCells. I don't want it to be visible- I just need to access this string when the row/cell is selected. What is the best way to do this?
Your best choice is probably to subclass UITableViewCell and add a string property. This can then be assigned either as a constant, or when setting up your cells in cellForRowAtIndexPath:.
class CustomCell: UITableViewCell {
var customString = "Default"
}
--------
func cellForRow(atIndexPath indexPath: IndexPath) -> UITableViewCell {
guard let cell: CustomCell = tableView.dequeueReusableCell(withReuseIdentifier: "identifier", indexPath: indexPath) as? CustomCell else {
return UITableViewCell()
}
cell.customString = "String"
return cell
}
func didSelectRow(atIndexPath indexPath: IndexPath) {
guard let cell: CustomCell = tableView.cellForRow(atIndexPath: indexPath) as? CustomCell else {
return
}
let stringFromCell = cell.customString
}
The above has not been compiled, so may not work word for word, but you get the principle.
Add a property selected to your model.
In cellForRow show/hide the string depending on the state of selected.
In didSelectRow toggle selected in the model and reload the row.

How to navigate to another view controller by click on button in collection view cell

I have a collection view controller with several cells. Each cell have a button and I want to go navigate to another view controller by ckick button on collection view cell. I can do it by click on the cell, but I want to do by click on button in the cell, not by click on cell.
I know how to do it by click on cell, for example:
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if let book = books?[indexPath.item] {
showBookDetail(book)
}
}
func showBookDetail(book: Book) {
let layout = UICollectionViewFlowLayout()
let bookDetailVC = BookDetailVC(collectionViewLayout: layout)
bookDetailVC.book = book
navigationController?.pushViewController(bookDetailVC, animated: true)
}
It's simple because I have indexPath and can send like parameter.
How I try to do it:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath) as! BookCell
cell.chapter = books?.bookChapters?[indexPath.item]
cell.goButton.addTarget(self, action: #selector(goChapter), forControlEvents: .TouchUpInside)
return cell
}
but how to send book to my func goChapter outside didSelectItemAtIndexPath?
func goChapter() {
let layout = UICollectionViewFlowLayout()
let bookChapterVC = BookChapterVC(collectionViewLayout: layout)
bookChapterVC.chapter = self.book?.bookChapters![0] // here I want to send separate chapter of the book
navigationController?.pushViewController(bookChapterVC, animated: true)
}
You can get the UIButton clicked index like this way:
func goChapter(sender: UIButton!) {
var point : CGPoint = sender.convertPoint(CGPointZero, toView:collectionView)
var indexPath = collectionView!.indexPathForItemAtPoint(point)
bookChapterVC.chapter = self.book?.bookChapters![indexPath.row]
navigationController?.pushViewController(bookChapterVC, animated: true)
}
Update your addTarget as below:
cell.goButton.addTarget(self, action: #selector(goChapter(_:)), forControlEvents: .TouchUpInside)
Hope this helps!
I found the easier solution:
in the function cellForItemAtIndexPath
cell.goButton.tag = indexPath.item
cell.goButton.addTarget(self, action: #selector(goChapter), forControlEvents: .TouchUpInside)
and then:
func goChapter(sender: UIButton!) {
let layout = UICollectionViewFlowLayout()
let bookChapterVC = BookChapterVC(collectionViewLayout: layout)
bookChapterVC.chapter = book?.bookChapters![sender.tag]
navigationController?.pushViewController(bookChapterVC, animated: true)
}

How can I add a UITapGestureRecognizer to a UILabel inside a table view cell? Swift2

I am using a custom table view cell. This cell has a label with outlet called chatNameLabel. Adding a UILongPressGestureRecognizer to this label never fires the associated event.
I'm guessing that the problem is that the UILabel is in a TableView and that the table/cell view is intercepting the taps. Can I do something about this?
All I want to do is perform some custom action when a UILabel is long pressed!
I believe this was answered in Objective-C however I am not familiar with the language at all and new to swift.
Here's the code I'm using:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let sessions = self.chatSessions where sessions.indices.contains(indexPath.row) {
let session = sessions[indexPath.row]
if session.sessionId == nil {
//DO A THING
}
// existing session id (existing chat)
else {
let cell = tableView.dequeueReusableCellWithIdentifier("ChatListCell", forIndexPath: indexPath) as! ChatListTableViewCell
cell.tag = indexPath.row
if(session.unreadChats) {
cell.indicatorImageView.tintColor = AppStyles.sharedInstance.indicatorActive
}
else{
cell.indicatorImageView.hidden = true
}
//Want to do gesture on this label below cell.chatNameLabel
cell.chatNameLabel.text = session.chatName
... Some more code not needed for question below this
Your class needs implement UIGestureRecognizerDelegate , then the below code should work.
myLabel.userInteractionEnabled = true
let tap: UILongPressGestureRecognizer = UILongPressGestureRecognizer(
target: self, action: #selector(tappedTheLabel))
tap.minimumPressDuration = 0.5
tap.delaysTouchesBegan = true
myLabel.addGestureRecognizer(tap)
tap.delegate = self
}
func tappedTheLabel(sender: UITapGestureRecognizer)
{
print("label hit \(sender)")
}

How to open an external link by clicking on an image using SWIFT2.0?

I am using SwiftyJSON to download images from external website and show them in table view. I want to click on a particular image and have it open an external URL. How to achieve this?
Basically what I am doing by button press (as show below), I want to do by clicking image.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! myCell
let str = TableData[indexPath.row].thumbnail
let imagePath = (str.substringToIndex(str.startIndex.advancedBy((str.characters.count)-11)))+".png" //Removing "-100x90.png" from each thumbnail path and appending extension .png later on to fetch original sized image
cell.myImageView.kf_setImageWithURL(NSURL(string: imagePath)!)
cell.myLabel.text = String(TableData[indexPath.row].date) + ":" + String(TableData[indexPath.row].title)
print(TableData[indexPath.row].permalink)
cell.myButton.tag = indexPath.row
cell.myButton.addTarget(self, action: "openURL:", forControlEvents: UIControlEvents.TouchUpInside)
print(cell.myButton.tag)
return cell
}
func openURL(sender:UIButton){
print("Button Pressed")
UIApplication.sharedApplication().openURL(NSURL(string: TableData[sender.tag].permalink)!)
}
Add a UITapGestureRecognizer to the image view in the cell:
let tapRecognizer = UITapGestureRecognizer(target: self, action: "openURL:")
cell.myImageView.addGestureRecognizer(tapRecognizer)
It works with following code:
let singleTap = UITapGestureRecognizer(target: self, action:"tapDetected:")
singleTap.numberOfTapsRequired = 1
cell.myImageView.userInteractionEnabled = true
cell.myImageView.tag = indexPath.row
cell.myImageView.addGestureRecognizer(singleTap)
func tapDetected(sender: UITapGestureRecognizer) {
UIApplication.sharedApplication().openURL(NSURL(string: TableData[(sender.view!.tag)].link)!)
}

Updating tableView code from Swift 1.2 - 2.0

I wrote this code to edit the row style (Swift 1.2 - Xcode 6.4)
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle
{
let edit = UITableViewRowAction(style: .Normal, title: "Edit") { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
let abb: AnyObject = self.frc.objectAtIndexPath(indexPath)
let editingView = self.storyboard?.instantiateViewControllerWithIdentifier("editingViewController") as! editingViewController
editingView.abbediting = abb
self.presentViewController(editingView, animated: true, completion: nil)
print("Edit Tapped")
print("Edited Button Clicked") }
edit.backgroundColor = UIColor.lightGrayColor()
let delete = UITableViewRowAction(style: .Normal, title: "Delete") { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
let abbDel = self.frc.objectAtIndexPath(indexPath) as! NSManagedObject
self.con?.deleteObject(abbDel)
print("Delete Button Clicked")
}
delete.backgroundColor = UIColor.redColor()
return [delete,edit]
}
I also set some actions, but now after I've updated to Xcode 7.0 and Swift 2.0, I've been getting errors telling me to return UITableViewCellStyle.
Can any body help me to update my code to something that works with Swift 2.0 please?
I think your code belongs to editActionsForRowAtIndexPath. The editingStyleForRowAtIndexPath needs to return editing style for the row, for example UITableViewCellEditingStyle.Delete. It is the style that shows when you tap the Edit button.

Resources