I want to update my tableview cells after an action is called in the editactionsForRowAtIndexPath function.
I've tried calling self.tableView.reloadData from the action handler, from the viewwillappear function and several other areas but it never reloads after the action is called.
What happens is a user swipes left and then they click the Confirm button which confirms an appointment and updates a value in the database.
The object is to have the function finish updating the value and then update the table by reloading so that in the cellforRowAtIndex can recycle through and color each cell a different color according to the values in the database.
But nothing seems to work.
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction] {
//confirm appointment
let confirm_action = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Confirm", handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
self.index_number = indexPath.row
let confirm_menu = UIAlertController(title: nil, message: "Which request?", preferredStyle: .ActionSheet)
let number_1 = UIAlertAction(title: "Choice 1", style: UIAlertActionStyle.Default, handler: self.confirm1)
let number_2 = UIAlertAction(title: "Choice 2", style: UIAlertActionStyle.Default, handler: self.confirm2)
let number_3 = UIAlertAction(title: "Choice 3", style: UIAlertActionStyle.Default, handler: self.confirm3)
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
confirm_menu.addAction(number_1)
confirm_menu.addAction(number_2)
confirm_menu.addAction(number_3)
confirm_menu.addAction(cancel)
self.presentViewController(confirm_menu, animated: true, completion: nil)
self.tableView.reloadData()
})
return [confirm_action]
}
//confirm choice1
func confirm1(alertAction: UIAlertAction!) -> Void {
tableView.sectionIndexColor = UIColor.greenColor()
//Update database entry to confirmed
let query = PFQuery(className: "Schedule")
query.getObjectInBackgroundWithId(object_ids[index_number]){
(Schedule: PFObject?, error: NSError?) -> Void in
//successfully loaded schedule request
if(error == nil && Schedule != nil) {
Schedule!["confirmed"] = "yes1"
dispatch_async(dispatch_get_main_queue()){
Schedule!.saveInBackground()
}
}
}
//update table
self.tableView.reloadData()
index_number = 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("schedules", forIndexPath: indexPath)
//load cell text depending on confirmed or not
if(confirmed_status[indexPath.row] == "yes1"){
cell.textLabel?.text = "\(users_names[indexPath.row]) \nPAID: \(paid_status[indexPath.row]) \nConfirmed for: \(location1) on \(date1)"
cell.textLabel!.textColor = UIColor.greenColor()
cell.editingStyle
}
else{
cell.textLabel?.text = "\(users_names[indexPath.row]) \nPAID: \(paid_status[indexPath.row]) \n#1 \(location1) on \(date1) \n#2 \(location2) on \(date2) \n#3 \(location3) on \(date3)"
}
//To enable word wrap for long titles
cell.textLabel!.numberOfLines = 0
return cell
}
Related
I have managed to create a tableview with an array or messages and when i tapped a tableview cell it shows an alertview and a uitextfield that you can change the text of the tableview. What i'm trying to do now is to save the tableview text ("message") when it changed. Because when I go to another view controller and go back it does not save. I am new on swift programming and wondering how can i achieve that. I have read some articles that i need to use nsuserdefaults but i am not familiar with that. here is my code below. Thanks guys.
class Messages: UITableViewController {
#IBOutlet var uitableView: UITableView!
var tField: UITextField!
var index: Int?
var msgArray: [String]!
var messages = ["Message 1", "Message 2", "Message 3", "Message 4", "Message 5", "Message 6"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let messagesCell = messages[indexPath.row]
cell.textLabel?.text = messagesCell
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let path = tableView.indexPathForSelectedRow
index = path?.row
changeMessage()
}
func changeMessage() {
let alert = UIAlertController(title: "Message", message: "Enter new preset message", preferredStyle: UIAlertControllerStyle.alert)
alert.addTextField(configurationHandler: configurationTextField)
let doneAction = UIAlertAction(title: "Done", style: UIAlertActionStyle.default, handler:{ (UIAlertAction) in
let modelString = self.tField.text
self.messages[self.index!] = modelString!
self.tableView.reloadData()
})
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(doneAction)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}
func configurationTextField(textField: UITextField!){
if (textField) != nil {
tField = textField
textField.text = messages[index!]
}
}
}
Try to use nsuserdefaults. In SWIFT 3
override func viewWillAppear(_ animated: Bool) {
//Get the array
if let array = UserDefaults.standard.object(forKey:"messages") as? Array<String> {
self.messages = array
}
}
func changeMessage() {
let alert = UIAlertController(title: "Message", message: "Enter new preset message", preferredStyle: UIAlertControllerStyle.alert)
alert.addTextField(configurationHandler: configurationTextField)
let doneAction = UIAlertAction(title: "Done", style: UIAlertActionStyle.default, handler:{ (UIAlertAction) in
let modelString = self.tField.text
self.messages[self.index!] = modelString!
UserDefaults.standard.set(self.messages, forKey: "messages") // Set the array with changes
self.tableView.reloadData()
})
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(doneAction)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}
let defaults = UserDefaults.standard
defaults.set("123", forKey: "oldString")
print("\(UserDefaults.standard.value(forKey: "oldString")!)")
This may help you.
class CoursesTableViewController: UITableViewController {
var nameOfCourse = "";
#IBAction func newCourse(_ sender: AnyObject) {
//1. Create the alert controller.
// var nameOfCourse = "";
let alert = UIAlertController(title: "New Course", message: "Enter the course name.", preferredStyle: .alert);
//2. Add the text field. You can configure it however you need.
alert.addTextField(configurationHandler: { (textField) -> Void in
textField.placeholder = ""
})
//3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
let textField = alert.textFields![0] as UITextField
self.nameOfCourse = textField.text!
print(self.nameOfCourse)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in
}))
// 4. Present the alert.
self.present(alert, animated: true, completion: nil)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cells = tableView.dequeueReusableCell(withIdentifier: "cells", for: indexPath) as? CoursesTableViewCell
cells?.textLabel.text = self.nameOfCourse
return cells!
}
Reload the table view after you've successfully set nameOfCourse (below print(self.nameOfCourse)).
I am trying to design View where i can show elements in sync with my Firebase Database. Every time element in my array changes it gets duplicated. Tried to use
self.tableView.reloadData()
but nothing changes. Tried as well
self.tableView.beginUpdates()
self.tableView.reloadRowsAtIndexPaths(NSArray.init(object: indexPath) as! [NSIndexPath], withRowAnimation: .Automatic)
self.tableView.endUpdates()
and it didn't work as previously.
I have tried unsuccesfully to perform reloading tableView in main thread using function
performSelectorOnMainThread
I am posting my code for you guys so someone can help me. Im quite new to iOS programming and i can't figure out when to reload data in tableView. Even after reading Apple's Documentation.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let alert = UIAlertController(title: "Akcja", message: "Wybierz akcję", preferredStyle: .ActionSheet)
let changeFieldNumberAction = UIAlertAction(title: "Zmień numer boiska", style: .Default, handler: {(action) in
self.showAlertOfChangingFieldNumber(indexPath)
})
let sendToRefereeAction = UIAlertAction(title: "Wskaż sędziego", style: .Default, handler: {(action) in
//self.championshitTournamentMode = false
})
let cancelAction = UIAlertAction(title: "Anuluj", style: .Cancel, handler: nil)
alert.addAction(cancelAction)
alert.addAction(changeFieldNumberAction)
alert.addAction(sendToRefereeAction)
self.presentViewController(alert, animated: true, completion: nil)
}
func showAlertOfChangingFieldNumber(indexPath: NSIndexPath) {
let fieldNumberAlert = UIAlertController(title: "Numer boiska", message: "Wpisz numer boiska", preferredStyle: .Alert)
fieldNumberAlert.addTextFieldWithConfigurationHandler({(textField: UITextField!) -> Void in
textField.placeholder = "Numer boiska"
textField.keyboardType = UIKeyboardType.NumberPad
})
let saveAction = UIAlertAction(title: "Zapisz", style: .Default, handler: {(action) -> Void in
let fieldNumberTextField = fieldNumberAlert.textFields![0] as UITextField
let fieldNumber = Int(fieldNumberTextField.text!)
self.updateGameFieldNumber(fieldNumber!, indexPath: indexPath)
})
let cancelAction = UIAlertAction(title: "Anuluj", style: .Cancel, handler: nil)
fieldNumberAlert.addAction(cancelAction)
fieldNumberAlert.addAction(saveAction)
self.presentViewController(fieldNumberAlert, animated: true, completion: nil)
}
func updateGameFieldNumber(fieldNumber: Int, indexPath: NSIndexPath){
let gameKey = games[indexPath.row].key
let ref = FIRDatabase.database().reference().child("games").child(gameKey)
games[indexPath.row].fieldNumber = fieldNumber
ref.updateChildValues(games[indexPath.row].toAnyObject() as! [NSObject : AnyObject])
//self.games.removeAtIndex(indexPath.row+1)
self.tableView.beginUpdates()
self.tableView.reloadRowsAtIndexPaths(NSArray.init(object: indexPath) as! [NSIndexPath], withRowAnimation: .Automatic)
self.tableView.endUpdates()
}
And my tableView delegate functions and function made for filling my array based on Firebase's database looks like that:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! GameViewCellTableViewCell
if games[indexPath.row].fieldNumber == 0 {
cell.fieldNumberLabel.text = "-"
} else {
cell.fieldNumberLabel.text = String(games[indexPath.row].fieldNumber)
}
cell.firstParticipantLabel.text = games[indexPath.row].firstParticipant
cell.secondParticipantLabel.text = games[indexPath.row].secondParticipant
cell.gameImage.image = UIImage(named: "tenisBall")
if games[indexPath.row].completed != true {
cell.backgroundColor = UIColor.init(red: 1, green: 109.0/255, blue: 95.0/255, alpha: 1)
} else {
cell.backgroundColor = UIColor.init(red: 160/255, green: 1, blue: 86/255, alpha: 1)
}
return cell
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.games.count
}
func getGames() {
let ref = FIRDatabase.database().reference().child("games")
ref.observeEventType(.Value, withBlock: {snapshot in
for item in snapshot.children {
let gameItem = GameItem(snapshot: item as! FIRDataSnapshot)
if(gameItem.tournamentName == self.tournamentName) {
self.games.append(gameItem)
}
}
self.tableView.reloadData()
})
}
It gets duplicated because instead of updating the value in your "games" array, you append the modified value to the array. This happens in the "getgames()" method.
inside the
func getGames()
after
self.games.append(gameItem)
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
how to make UITableview editable, I am using EDITActionsForRowAtIndexPath delegate for editing cell
My code :
let infoAction = UITableViewRowAction(style: UITableViewRowActionStyle.Destructive, title: "More", handler: { (action , indexPath) -> Void in
let MoreInfo = UIAlertController(title: "More", message: nil, preferredStyle: .ActionSheet)
MoreInfo.addAction((UIAlertAction(title: "Flag This conversation", style: .Default, handler: { (UIAlertAction) -> Void in
print("flaged")
self.tableView.setEditing(true, animated: true)
self.tableView.editing = true
})))
MoreInfo.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
print("Cancel")
self.presentViewController(MoreInfo, animated: true, completion: nil)
})
don't use uialert, try this snippet:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
let deleteClosure = { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
println("Delete button pressed")
}
let moreClosure = { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
println("More button pressed")
}
let deleteAction = UITableViewRowAction(style: .Default, title: "Delete", handler: deleteClosure)
let moreAction = UITableViewRowAction(style: .Normal, title: "More", handler: moreClosure)
return [deleteAction, moreAction]
}
this should show 2 buttons: one red with delete text and one gray with more text; you can customize as you prefer :)
source: http://pablin.org/2014/09/25/uitableviewrowaction-introduction/
I have a UIViewController, with a UICollectionView with a (custom) UIButton at the reusableViewCell.
I have the following code for a TableView
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let shareRaceAction = UITableViewRowAction(style: .Default, title: "Share") {
(action: UITableViewRowAction, indexPath: NSIndexPath) -> Void in
let sheet = UIAlertController(title: nil, message: "Teilen mit", preferredStyle: .ActionSheet)
let race = self.races[indexPath.row]
//
let twAction = self.newAction(SLServiceTypeTwitter, race: race)
sheet.addAction(twAction)
//
let fbAction = self.newAction(SLServiceTypeFacebook, race: race)
sheet.addAction(fbAction)
//
let cancelAction = UIAlertAction(title: "Abbrechen", style: .Cancel, handler: nil)
sheet.addAction(cancelAction)
self.presentViewController(sheet, animated: true, completion: nil)
}
How can this Code be implemented for a UICollectionView with a custom button?
Help is very appreciated