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.
Related
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)
}
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
I am trying have the user to modify/delete default text in a tableview, I have tried the following code witch works but as soon as the user goes to the other view controller and back (or leaves the app and comes back), the text goes back to being the default text.
How could I have it work?
I have posted the entire code for the tableView so you can have an overview of what I could have done wrong.
thank you !
var places = [Dictionary<String,String>()]
var activePlace = -1
class TableViewController: UITableViewController {
func companyNameUpdatedAlert(title: String, error: String, indexPath: Int) {
let alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.Alert)
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
textField.placeholder = "Enter new text"
}
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
let lat = places[indexPath]["lat"]!
let lon = places[indexPath]["lon"]!
places.removeAtIndex(indexPath)
places.insert(["name" : alert.textFields![0].text!, "lat" : lat, "lon" : lon], atIndex: indexPath)
self.tableView.reloadData()
}))
self.presentViewController(alert, animated: true, completion: nil)
}
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let changeText = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Change text" , handler: { (action:UITableViewRowAction, indexPath:NSIndexPath) -> Void in
self.companyNameUpdatedAlert("Update text", error: "enter text below", indexPath: indexPath.row)
})
let deleteAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete" , handler: { (action:UITableViewRowAction, indexPath:NSIndexPath) -> Void in
places.removeAtIndex(indexPath.row)
tableView.reloadData()
})
return [changeText, deleteAction]
}
override func viewDidLoad() {
//save start
if NSUserDefaults.standardUserDefaults().objectForKey("places") != nil {
places = NSUserDefaults.standardUserDefaults().objectForKey("places") as! [Dictionary]
//save stop
super.viewDidLoad()
if places.count == 1 {
places.removeAtIndex(0)
places.append(["name":"Long press on map to add location","lat":"90","lon":"90"])
}
if NSUserDefaults.standardUserDefaults().objectForKey("places") != nil {
places = NSUserDefaults.standardUserDefaults().objectForKey("places") as! [Dictionary]
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = places[indexPath.row]["name"]
return cell
}
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
activePlace = indexPath.row
return indexPath
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "newPlace" {
activePlace = -1
}
}
override func viewWillAppear(animated: Bool) {
tableView.reloadData()
}
}
When you edit the table you should persist your data in the NSUserDefaults. Otherwise you are just changing the class property which is reloaded from the original NSUserDefaults each time the class loads.
Try this inside your UIAlertAction closure:
NSUserDefaults.standardUserDefaults().setObject(places, forKey: "places")
NSUserDefaults.standardUserDefaults().synchronize()
I am trying to implement an alarm clock app just like apple's Clock app.On the click of Edit button on the left hand side I want to make table enter into Editing mode with red circles on left side of every cell(custom UITableViewCell) And on the click of that red circle want to show "Delete" button/action on the right side.
I have been trying a lot and went through many sites but still could not figure out. Can someone please see what mistake I am making?
I have referred below and many others links:
How to enable swipe to delete cell in a TableView?
UITableViewCell, show delete button on swipe
class SavedAlarmListViewController: UIViewController,UITableViewDataSource,UITableViewDelegate{
#IBOutlet weak var tableView: UITableView!
var alarms = [AlarmDataObject]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.navigationItem.leftBarButtonItem = self.editButtonItem()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
refreshList()
}
func refreshList() {
alarms = AlarmsList.sharedInstance.allSavedAlarms()
tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return alarms.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! AlarmTableViewCell
// custom code to set data ....
return cell
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true // all cells are editable
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let alarm = alarms.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
AlarmsList.sharedInstance.removeAnAlarm(alarm)
}
}
}
class AlarmTableViewCell:UITableViewCell {
// IBOutlets
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
You should implement
tableView(_:editingStyleForRowAtIndexPath:) and return .Delete
My code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject) -> PFTableViewCell{
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as!
CustomTableViewCell!
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CustomCell")
}
// Extract values from the PFObject to display in the table cell
if let username = object["username"] as? String {
cell.customUser.text = username
}
if let title = object["Title"] as? String {
cell.customTitle.text = title
}
// Display image
var initialThumbnail = UIImage(named: "Swarm_Bee.png")
if let thumbnail = object["imageFile"] as? PFFile {
thumbnail.getDataInBackgroundWithBlock{
(imageData, error) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.customImage.image = image
}}
}
return cell
}
receives the following error
overriding method with selector 'tableView:cellForRowAtIndexPath:object:' has incompatible type '(UITableView,NSIndexPath,PFObject) -> PFTableViewCell'
I have looked up all the compatibility errors (removing !). Another post had a similar issue:
Parse SDK 1.7.1 not working in Xcode 6.3
But only their number 3 error. All other issues in that post were addressed, but this error remains. Any solutions or recommendations of where to look?
I figured it out. Use the following override function:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
//...
}
The difference is making the PFObject and the PFTableViewCell optionals.