ListView swipe to delete - nativescript

Is there a way to achieve that in NativeScript's ListView?
RadListView has this mechanism built in, but ListView has better performance for my layout.
I've been searching in the documentation and it appeared that there isn't any, so I looked for a way to do it in the native elements: iOS's UITableView and Android's ListView-
For UITableView I found this blogpost that suggests that:
It takes just one method to enable swipe to delete in table views:
tableView(_:commit:forRowAt:)
So how do I translate this to NativeScript?
The swift code from the post is:
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
Also, is there a straightforward way to do that in Android's ListView?

Related

How to get the right row in a #IBsegueAction function?

I can segue from an embedded UIKit tableview to a SwiftUI view, with the necessary data. I select the indexPath.row with a tableView(_didSelectRowAt).
However, the #IBSegueAction takes place before the didSelectRowAt. This makes the detailView lag one selected row: it shows the previously selected row.
I tried to put the didSelectRowAt first, tried to embed them: no chance
I saw in a WWDC video that it should be possible lo select the right row, but can't figure out the right syntax from this short segment (about minute 6:00)
https://developer.apple.com/videos/play/wwdc2019/231/
#IBSegueAction func MeasurementDetail(_ coder: NSCoder) -> UIViewController? {
return UIHostingController(coder: coder, rootView: PointDetailSwiftUIView(pointDetail: measurements[selectedMeasurementRow]))
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedMeasurementRow = indexPath.row
}
How do I solve the problem?
In that WWDC session, Tanu doesn't care when UIKit calls tableView(_:didSelectRowAt:). Instead, her #IBSegueAction asks the table view for the selected row, by using tableView.indexPathForSelectedRow.
Make sure you have a tableView outlet connected to your table view. You already have a tableView outlet if your view controller is a subclass of UITableViewController. Then use tableView.indexPathForSelectedRow:
#IBSegueAction func MeasurementDetail(_ coder: NSCoder) -> UIViewController? {
guard let row = tableView.indexPathForSelectedRow?.row else { return nil }
let detailView = PointDetailSwiftUIView(pointDetail: measurements[row])
return UIHostingController(coder: coder, rootView: detailView)
}

tableview trailingSwipeActionsConfigurationForRowAt crack in ios11

I Use trailingSwipeActionsConfigurationForRowAt in IOS11 but when swipe multiple then app cracked.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .normal, title: "Delete") { action, view, completionHandler in
print("Deleting!")
completionHandler(false)
}
delete.backgroundColor = UIColor.red
let config = UISwipeActionsConfiguration(actions: [delete])
config.performsFirstActionWithFullSwipe = false
return config
}
and some error
*** Assertion failure in -[UISwipeActionController swipeHandlerDidBeginSwipe:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3694.4.18/SwipeActions/UISwipeActionController.m:268
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No occurrence for index path (null)'
TL;DR - look if you are doing something with your data (e.g. reloading) between your swipes.
I had similiar issue when I swipe-to-delete one cell (leaving it in edit mode - delete action visible) and then trying to swipe another caused that my app crashed. In my case it was because reloading table data in between those swipes.
Swipe-to-delete gesture calls willBeginEditingRowAtIndexPath and didEndEditingRowAtIndexPath methods on UITableViewDelegate object. In the latter one I called tableView.reloadData(). When I swipe-to-delete other cell I got didEndEditingRowAtIndexPath method called for the first cell (also reloading data) and just after that system called willBeginEditingRowAtIndexPath for the other cell and the data was out of sync and UIKit crashes.
When I removed the code that reloading data in didEndEditingRowAtIndexPath method my app won't crashes anymore :)
You need to implement tableView(_:editActionsForRowAt:).
As a minumum, return empty array, but not nil:
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
return []
}
I just used UIViewController + UITableViewDataSource & UITableViewDelegate combination instead of using UITableViewController for the swiping issue.

How to use two tableview in one view?

I have two table view in one view container. I insert each of them to the container.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
self.storyboard?.instantiateViewController(withIdentifier: "ChildTableView") as! ChildTableViewController
childTV.updateTable(id: indexPath.row)
}
I need to update second tableview when first tableview cell clicked.
How i can do this?
Okay, I think I see the problem. The way you've done this is with two UITableViewControllers and their table views. So now you have a problem communicating between the two table view controllers. But consider this: if you've truly created child view controllers, the table view controllers are children of the same parent. So the first table view controller can get its parent view controller, then get the parent's child view controllers, then get the second child view controller, and that must be the second table view controller.
In other words, if your view controller hierarchy is:
ParentViewController
TableViewController1
TableViewController2
... then TableViewController1 can say:
let tvc2 = self.parent!.childViewControllers[1] as! TableViewController2
... and now you have established a line of communication between them. So now table view controller 1 can talk to table view controller 2 and tell it to update its table. You will need to have a method in table view controller 2 that table view controller 1 can call, in order to hand it any needed data and tell it what to do.
in Second TableView:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ChildTableViewController.updateTable(sender:)), name: NSNotification.Name(rawValue: "updateChild"), object: nil)
}
func updateTable(sender:NSNotification){
tableView.reloadData()
}
in First TableView:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
selectedItem["id"]=indexPath.row
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateChild"),object:selectedItem)
}

I have a bug with a Swift table view cell action

I'm using editActionsForRowAtIndexPath with Swift to add a option to my app cells.
My app is a homework list app, where you can set its subject, its category, the date you need it ready for and add a description. Also, there is a option that when you swipe the cell to the left you will be able to set the homework as Done. To show that, I created a label and added it to the cell, that if the homework is pending, the label will be Pending. If it was set as done, it will be Concluded. The thing is that when I'm setting ONE cell as done, it is setting all the other cells, which is not what I want.
The code I'm using to say that I only want THIS cell to be set as done is this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("AtivCell") as? AtivCell {
if !isPending {
pendencia[indexPath.row] = false
saveData()
}
cell.configureCell(materias[indexPath.row], data: datas[indexPath.row], descricao: descricoes[indexPath.row], pendencia: pendencia[indexPath.row], categoria: categorias[indexPath.row])
return cell
} else {
return AtivCell()
}
}
Here is the entire project, I really need help, I don't think I did anything wrong.
I've tried deleting the app from my iPhone (where I'm testing), tried closing Xcode, tried everything, it just does not work!!!
Link: https://github.com/HenriqueDoura/Agenda/tree/master/agenda-app
You should be using dequeueReusableCellWithIdentifier with the forIndexpath parameter, which always returns a cell. The one you've used requires you to test if it's nil and create one, which you are doing in the else clause and then not initialising it.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("AtivCell", forIndexPath: indexPath) as? AtivCell {
cell.configureCell(materias[indexPath.row], data: datas[indexPath.row], descricao: descricoes[indexPath.row], pendencia: pendencia[indexPath.row], categoria: categorias[indexPath.row])
return cell
}
You can use your current function if you want, but you need to declare cell as var, and create it if dequeue returns nil, and then set its values.
Also your !isPending code will not work properly. Within editActionsForRowAtIndexPath, you should be setting pendencia[indexPath.row] = false.

Passing an image when taped on uicollectionview to a detail view controller in swift

Ive been at this for a while but cant seem to crack it in swift
I want a user to be able to select an image in uicollectionView and for that image to appear in a detailed view controller, i can do this quite easily with a peice of text,
and i can do this when there is a static array of images preloaded. but i cant seem to get anywhere with a collectionview which is loaded with images from a camera.
I understand i need to use
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
}
and this function to isolated selected cell.
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
}
I do have these outlets
#IBOutlet weak var collectionView: UICollectionView!
var images = [UIImage]()
image picker stores all images to this array by
images.insert(newImage, atIndex: 0)
when the array would be passed to the detailviewcontroller, i understand that would have to be copied into another local array and then how would i get the current image that was highlighted to be shown first, perhaps using indexPath.Row
Regards
I'm not using segues, and actually I don't quite understand what your problem is, but I'll try to show you how it could be achieved.
First of all, you have an array with images, so I believe your image should be accessed as images[indexPath.row]
let's suppose that you already have UIViewController class with UIImageView in it.
if so, you can write something like that:
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.presentViewController(myVC, animated: true, completion: nil)
}
for modal or
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.navigationController?.pushViewController(myVC, animated: true)
}
if you want to show it as navigational.
I believe that with segues it's basically the same but I think you have to use func prepareForSegue for, you know, preparing the segue (func performSegueWithIdentifier will just perform it). In prepareForSegue you should check identifier of your segue
if segue.identifier == "myIdentifier" {
//your code here
}
and if this identifier is right, put your commands to your myVC there.

Resources