I'm a beginner of Swift, and I searched a lot of stuffs, but couldn't figure out and decided to post my first question ever here.
I have a table view to show tweets by using twitter fabric and I use UITableViewRowAction to present two options to users when a swipe is done on a row, "funnelOne" and "funnelTwo", to categorize their tweets by adding tags to each tweet.
In the view controller, I add two functions to make an alert and get a value of 'funnelTag' to store it to my core data.
However, I am not sure if I can correctly store the number to the core data because somehow different cell would be deleted if I push one of swipeable buttons. I know I can write a code within 'func tableView' to delete the row, but how I can get access from out of 'func tableView' to delete the row successfully??
If it can be resolved, I should be able to successfully store the value to my core data.
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) as? CustomTableViewCell
let funnelOne = UITableViewRowAction(style: .Default, title: "funnel") {
(action, indexPath) -> Void in
funnelTag = 1 // funnelTag is Int I want to store in my Core Data
cell!.tag = funnelTag
// self.tweets.removeAtIndex(indexPath.row) - I know this is working
tableView.setEditing(false, animated: true)
}
let funnelTwo = UITableViewRowAction(style: .Default, title: "funnel") {
(action, indexPath) -> Void in
funnelTag = 2
cell!.tag = funnelTag
tableView.setEditing(false, animated: true)
// self.tweets.removeAtIndex(indexPath.row)
}
These are two functions I add. if I implement these functions, top row would be deleted even though I want to delete other row... the first function, funnelTweet() is properly working, but the second function does not seem to work correctly..
func funnelTweet(cell: CustomTableViewCell){
let index: Int = cell.tag
if SettingStore.sharedInstance.isNoAlert(){
self.submitFunnel(index, cell: cell)
} else {
self.alert = UIAlertController(title: NSLocalizedString("stock_confirm_funnel", comment: ""), message: nil, preferredStyle: .Alert)
self.alert!.addAction(UIAlertAction(title: NSLocalizedString("common_ok", comment: ""), style: .Destructive) { action in
self.submitFunnel(index, cell: cell)
})
self.alert!.addAction(UIAlertAction(title: NSLocalizedString("common_cancel", comment: ""), style: .Cancel) { action in
cell.moveToLeft()
})
self.presentViewController(self.alert!, animated: true, completion: nil)
}
}
func submitFunnel(index: Int, cell: CustomTableViewCell){
var tweet = self.tweets[index]
// store to local storage
TagStore.sharedInstance.saveData(tweet.createdAt, funnelTag: funnelTag, id: tweet.tweetID)
self.tweets.removeAtIndex(index)
self.tableView!.reloadData()
}
Thank you for your help!
In the Second function you have not initialized the index before using it.
func submitFunnel(index: Int, cell: CustomTableViewCell){
// Initialize index here before using it in the next statement.. that is give it a value, otherwise it will return nil
var tweet = self.tweets[index]
// store to local storage
TagStore.sharedInstance.saveData(tweet.createdAt, funnelTag: funnelTag, id: tweet.tweetID)
self.tweets.removeAtIndex(index)
self.tableView!.reloadData()
}
Related
I have a UITableView with 2 sections, in the first one there is the cells that each represent the different item from an array, and the second one calls a UIAlertController with a textfield. I want whatever I write in the textfield to show in the first section of the tableView. My code currently is:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.section {
case 0:
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
UserDefaults.standard.set(selectedCaseSolutionsForCell[indexPath.row], forKey: "ollShowAlg\(selectedCaseID)")
print("OLL Case with ID \(selectedCaseID) had its main algorithm changed to \(selectedCaseSolutionsForCell[indexPath.row])")
let newMainSolve : String = UserDefaults.standard.string(forKey: "ollShowAlg\(selectedCaseID)")!
print("THE ALGORITHM IS NOW \(newMainSolve)")
case 1:
tableView.cellForRow(at: indexPath)?.accessoryType = .none
let alert = UIAlertController(title: "Add New Algoritm", message: "", preferredStyle: .alert)
alert.addTextField()
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("Text field: \(textField!.text!)")
}))
present(alert, animated: true)
default:
return
}
}
How can I add the textfield input to the array and then show that at the end of the UITableView? This question is not a duplicate as I'm not using a custom cell and don't have an IBOutlet or IBAction for it.
I'll assume the table's data source is an array of string named data. Something like this:
fileprivate var data: [String] = []
Then all you have to do after this line print("Text field: \(textField!.text!)") is add the following:
self.table.beginUpdates()
self.data.append(textField!.text!)
self.table.insertRows(at: [IndexPath(item: self.data.count - 1, section: 0)], with: .bottom)
self.table.endUpdates()
My code is this:
let alrController = UIAlertController(title: "Membri", message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
tableView.backgroundColor = UIColor.white
alrController.view.addSubview(tableView)
let cancelAction = UIAlertAction(title: "Esci", style: UIAlertActionStyle.cancel, handler: {(alert: UIAlertAction!) in})
alrController.addAction(cancelAction)
self.present(alrController, animated: true, completion:{})
I want to populate (but I don't know how) the tableView with this values in my array: names["name1","name2","name3"]
Can someone help me?
To populate an action sheet, you don't add a tableView. Instead, you simply add the actions and it will create and manage the tableView privately.
For a recent tutorial, see UIAlertController Examples
The idea is that you'd create an UIAlertAction for each String in your array, including a closure for what to do when user taps that action row.
for name in names
{
let namedAction = UIAlertAction(title: name, style: .default)
{ (action) in
// do something when this action is chosen (tapped)
}
alrController.addAction(namedAction)
}
You need to implement the following tableView dataSource methods in order to populate this data and also set tableView datasource to alertController like below:-
tableView.dataSource = alertController
TableView DataSource method
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell: yourCustomCell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as? yourCustomCell
else {
fatalError("yourCustomCell not found")
}
cell.textLabel.text = names[indexpath.row]
return cell
You can use custom UIViewController transition to achieve this kind of functionality.
This link: https://github.com/pgpt10/Custom-Animator will give you an idea of how you can achieve that.
I am preparing a table in which when I swipe the cell I need to get two rounded buttons. Each button should have one image and and a label.
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
var hello = UITableViewRowAction(style: .Default, title: "Image") { (action, indexPath) in
// do some action
if let buttonImage = UIImage(named: "Image") {
// self.bgColor = UIColor.imageWithBackgroundColor(image: buttonImage, bgColor: UIColor.blueColor())
}
return editButtonItem()
}
First of all, there are some problems with your code :
You return the result of editButtonItem() method, which basically discards your hello action. I'm gonna assume from the name of it, that this method returned a single action, and not two as you wanted.
In your action handler, you tried to set the background on self. Blocks capture variables from their parent scope, so self in this block didn't relate to hello action, but rather to the class in which your editActionsForRowAtIndexPath method was implemented.
How to achieve what you need (two buttons with title and image) :
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
var firstAction = UITableViewRowAction(style: .Default, title: "First") { (action, indexPath) in
// action handler code here
// this code will be run only and if the user presses the button
// The input parameters to this are the action itself, and indexPath so that you know in which row the action was clicked
}
var secondAction = UITableViewRowAction(style: .Default, title: "Second") { (action, indexPath) in
// action handler code here
}
firstAction.backgroundColor = UIColor(patternImage: UIImage(named: "firstImageName")!)
secondAction.backgroundColor = UIColor(patternImage: UIImage(named:"secondImageName")!)
return [firstAction, secondAction]
}
We create two separate actions, assign their background colors to use pattern images and return an array containing both our actions. This is the most you can do to alter the appearance of UITableViewRowAction - we can see from the docs, that this class doesn't inherit from UIView.
If you wanted to customize the appearance more, you should look for an external library or implement your own solution from the scratch.
Alright, I am testing around a bit with core data, something I recently have started to discover, basically, what i have so far, is a single view app, that has a data source, and i can press a button and it brings up and alert, which from there i can add names to the list, and delete names from the list, i can close my app and still maintain my data. here is the issue/question, i am trying to do an update, so i can edit names in the list, i have a uibutton set up on my prototype cell, and i have it linked to my viewController, and have a function set inside the IBAction for the button. however, the button does not appear in my sim at run time.
here i have some code.
this is code for the edit button, and its function:
#IBAction func editButton(sender: AnyObject) {
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// 2
let alert = UIAlertController(title: "Update",
message: "Please enter the new name.",
preferredStyle: .Alert)
// 3
let updateAction = UIAlertAction(title: "Save",
style: .Default){(_) in
let nameTextField = alert.textFields![0]
self.updateName(indexPath.row, newName: nameTextField.text!)
self.tableView.reloadData()
}
// 4
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alert.addTextFieldWithConfigurationHandler(nil)
alert.addAction(updateAction)
alert.addAction(cancelAction)
// 5
self.presentViewController(alert, animated: true, completion: nil)
}
here is my cellForRowAtIndexPath func
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")!
let people = peoples[indexPath.row]
cell.textLabel!.text = people.name
return cell
}
here is an image of my storyboard
Storyboard
if you need further information or code, please let me know and i will provide it.
I currently have a sidebar menu in an iOS 9.2 app running on Xcode 7.2 written in Swift 2 that allows the user what data to load to populate the view. I'm using SWRevealViewController to create that sidebar. I have a container view controller which has the front page and the sidebar page listing all the options the user has. Each time the user selects a cell from the sidebar table, it performs a segue that allows the front page to be refreshed. What I want to do is to allow the user to delete a cell from the table with a long press. I'd like to show an AlertViewController to confirm the user's decision, and if "Yes" is selected, I want to delete the cell, and select the very first item in the table. I've tried following the instructions from Long press on UITableView
but I keep getting the error "unrecognized selector sent to instance"
Here's the code that I'm using for setting up the gestureRecognizer in the cellForRowAtIndexPath function:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell;
cell.textLabel!.text = tableArray[indexPath.row];
let holdToDelete = UILongPressGestureRecognizer(target: cell, action: "longPressDelete");
holdToDelete.minimumPressDuration = 1.00;
cell.addGestureRecognizer(holdToDelete);
return cell;
}
And here's the longPressDelete function:
func longPressDelete(sender: UILongPressGestureRecognizer) {
let alert: UIAlertController = UIAlertController(title: "Please Confirm", message: "Are you sure you want to delete this car from your database?", preferredStyle: .Alert);
alert.addAction(UIAlertAction(title: "Yes", style: .Destructive, handler: { (UIAlertAction) -> Void in
if let tv = self.tableView {
let point: CGPoint = sender.locationInView(self.tableView);
let indexPath: NSIndexPath = self.tableView.indexPathForRowAtPoint(point)!;
tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade);
NSUserDefaults.standardUserDefaults().removeObjectForKey("fillUp" + tableArray[indexPath.row]);
NSUserDefaults.standardUserDefaults().removeObjectForKey("services" + tableArray[indexPath.row]);
tableArray.removeAtIndex(indexPath.row);
NSUserDefaults.standardUserDefaults().setObject(tableArray, forKey: "cars");
self.deleted = true;
self.performSegueWithIdentifier("tableToDashboard", sender: self);
}
}));
alert.addAction(UIAlertAction(title: "No", style: .Default, handler: nil));
self.presentViewController(alert, animated: true, completion: nil);
}
Here's the prepareForSegue function:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (deleted) {
let indexPath: NSIndexPath = NSIndexPath(forRow: 0, inSection: 0);
fillUpKey = "fillUp" + tableArray[indexPath.row];
servicesKey = "services" + tableArray[indexPath.row];
localFillUpArray = [fillUp]();
} else {
let indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow!;
fillUpKey = "fillUp" + tableArray[indexPath.row];
servicesKey = "services" + tableArray[indexPath.row];
localFillUpArray = [fillUp]();
}
}
What I'd like to happen is that the user deletes the item in the cell, and the app then performs a segue to the front screen after loading the information from another source. Thanks for taking the time to read this and possibly provide an answer. I hope I haven't made a rookie mistake somewhere.
Incorrect Selector
let holdToDelete = UILongPressGestureRecognizer(target: self,
action: "longPressDelete:");
: after longPressDelete indicates that the method func longPressDelete(sender: UILongPressGestureRecognizer) actually accepts parameters.
self for target, assuming that the selector belongs to the same class that registered it.
The current selector "longPressDelete" would match a method signature without parameters:
func longPressDelete() { }
Very simple example if you want to select cell in uitableview
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.longTap))
cell.addGestureRecognizer(longGesture)
// longTap
func longTap(gestureReconizer: UILongPressGestureRecognizer) {
print("Long tap")
let longPress = gestureReconizer as UILongPressGestureRecognizer
_ = longPress.state
let locationInView = longPress.location(in: tableview)
let indexPath = tableview.indexPathForRow(at: locationInView)
// whatever you want with indexPath use it //
}