I've have been sniffing around to find the solution but up until now its fruitless. What I want to do is to determine if a certain cell disappeared from screen.
Here's the code i have been trying:
func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let indexPathWatchCell = NSIndexPath(forRow: 4, inSection: 0)
if ((tableView.indexPathsForVisibleRows?.contains(indexPathWatchCell)) == nil){
NSLog("it disappeared!!")
}
}
Unfortunately its not working, any ideas?
EDIT:
for clarity, what I want to accomplish is set the size of the cell to CGFLOAT(44) when it disappeared in view
contains method return Boolean value if the object contains other wise return false, so you need to check for that not for nil so change your code like this.
if (tableView.indexPathsForVisibleRows?.contains(indexPathWatchCell)){
NSLog("it not disappeared!!")
}
else {
NSLog("it's disappeared!!")
}
Or if you just want to know for "disappeared" than you can use !(not) with if
if (!tableView.indexPathsForVisibleRows?.contains(indexPathWatchCell)){
NSLog("it disappeared!!")
}
Related
I have attached a image.
This is the iPhone's default reminder app.
Like this, I want to make a gray background when the drag cell overlap.
Here is what I tried: ;But it looks ugly in the emulator.
var beforeTouch: IndexPath?
func tableView(_ tableView: UITableView,
targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath,
toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
if let cell = tableView.cellForRow(at: proposedDestinationIndexPath) {
if (self.beforeTouch != sourceIndexPath)
&& (sourceIndexPath != proposedDestinationIndexPath) {
if self.beforeTouch == nil {
cell.setSelected(true, animated: false)
} else {
cell.setSelected(true, animated: false)
tableView.cellForRow(at: beforeTouch!)?.setSelected(false, animated: false)
}
}
self.beforeTouch = proposedDestinationIndexPath
}
return proposedDestinationIndexPath
}
In this code, I used below method.
func tableView(_:, targetIndexPathForMoveFromRowAt:, toProposedIndexPath:) -> IndexPath
It seems executed every time when drag and can trace the cell by using the IndexPath of the parameter.
Also, I think there will be a performance problem because the 'cell.setSelected()' is used in a tableView function that is continuously called while dragging. I also have the problem of having to store the indexPath of the previous cell in the storage property of the class, so I am looking for another way.
I think there will be a traditional way to this issue.
Can someone help on how I can achieve it?
Need a little help from you, I am working on Table View where I have an Array which is received from server. The Array is nothing but Multiple Choice Options. It looks something like this
a. Table
b. Bottle
c. Hat
d. Bucket
e. None of the Above.
What I Want ?
I want to select multiple answers i.e Table , Bottle , Bucket and it is shown by checkbox marked. Which I have managed to do it well. And when last option i.e None of the Above is selected I want to deselect all the above checked mark options and just show the None option checked, even this is working.
Where I am stuck?
When "None of the Above" is in selected mode and I tap on any other option then "None" should be deselected. This is not working , I don't know whats wrong here. Please help. TIA
Here's my didSelect Method
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if selectedString == "None of the above" {
selectedIndex = indexPath.row
self.isNoneSelected = true
for index in tableView.indexPathsForSelectedRows!
{
tableView.deselectRowAtIndexPath(index, animated: true)
}
}
And my None option will always be at last position, so even array.lastobject will work I guess
You are making it too complicated here. All you need is an array of boolean to store the selected states, and reloadData() for the tableView, if you add an UIImageView to represent selected state.
It's not a good idea to call tableView.deselectRow() for every row directly
var selected = Array(repeating: false, count: 5)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
//let cell = whatever
cell.checkMark.isHidden = !selected[indexPath.row]
//return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
selected[indexPath.row] = !selected[indexPath.row]
if (indexPath.row == selected.count - 1 ) {//if 'None' is selected
for i in 0..<selected.count-2 {
selected[i] = false
}
} else { //all other rows will deselect the 'None' row
selected[selected.count - 1 ] = false
}
tableView.reloadData()
}
Ok I can't be sure, but it looks like this code handles all selection events, right? If so, there appear to be several problems:
1) selectedIndex is only set if they select the last item. I suspect that is not what you want, but I cannot be sure.
2) same for self.isNoneSelected = true - I suspect you want to use this value in other methods to see if that is the selected item, but you don't seem to have any code to turn it off again.
3) you turn off the selection for all the other items, but don't turn on selection for "none" - but that might have already happened in the event, I don't see the rest of the code there.
So I think you want something like this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedIndex = indexPath.row
if selectedString == "None of the above" {
self.isNoneSelected = true
for index in tableView.indexPathsForSelectedRows!
{
tableView.deselectRowAtIndexPath(index, animated: true)
}
} else {
self.isNoneSelected = false
//NOTE I AM NOT AT MY MACHINE SO I DON'T KNOW THE EXACT SYNTAX HERE
//THE IDEA IS TO GET THE INDEX PATH OF THE LAST ITEM SO WE CAN TURN IT OFF
tableView.deselectRowAtIndexPath(NSIndexPath.indexPathForRow(mydatasource.count-1, inSection:0), animated: true)
}
}
I am looking to captured image tap event on the first record of UITableView, when user taps I cell.imageAvtar I just want to capture that event.
This is the code I am using
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("details", forIndexPath: indexPath) as! AccountCell
if (indexPath.row == 0) {
(cell.contentView.viewWithTag(101) as! UIImageView).image = UIImage(named: "no_image_available.jpg")
}
return cell
}
But (cell.contentView.viewWithTag(101) is returning as nil.I have tried (cell.contentView.viewWithTag(100) tried (cell. imageAvtar.viewWithTag(101) as well.
check your imageView's tag in interface builder or storyboard if it is 0 make it 101 and retry..
you can also check
for subView in cell.contentView.subView {
print("subView tag --> \(subView.tag)!")
}
try this in your cellForRowAtIndexPath
Try,
cell.viewWithTag(101) or self.view.viewWithTag(101) if tag is unique(i.e. if you are not using this tag at other place).
Second thing you have to add gesture recognizer to capture event on it. How you come to know that it's returning nil ? It may not return nil. You are making another mistake. Make sure that no_image_available.jpg is properly available in project!
Another thing is make sure that you have set tag properly.
I have used IBOutlets as vadian and jrturton advised.
This is the working code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("details", forIndexPath: indexPath) as! AccountCell
if (indexPath.row == 0) { let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:Selector("imageTapped:"))
cell.imageAvtar.userInteractionEnabled = true
cell.imageAvtar.addGestureRecognizer(tapGestureRecognizer)
}
}
func imageTapped(img: AnyObject)
{
print("event captured")
//your logic comes here
}
I have a tableView where I want to display different Cells depending on what a variable seguedDisplayMonth is set to. Is this possible and if so can I get any hint on how to do this? I've tried the following but it doesn't seem to work.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Income Cell", forIndexPath: indexPath)
let income = myIncomeArray[indexPath.row]
if seguedDisplayMonth == "All" {
var text = "\(income.money) kr"
cell.textLabel?.text = text
cell.detailTextLabel?.text = income.name
}
return cell
}
I also thought that maybe I need to reload the data after changing the seguedDisplayMonth which gets changed from a different tableView and through a segue.
Call mcTableSwag.reloadData() once seguedDisplayMonth is changed. (Likely call it in the function that actually changes seguedDisplayMonth.
Alternatively you could reload certian cells with some method like reloadVisibleCellsAtIndexPath(...) (Im not sure what it is called exactly, but it should be on the Apple UITableView documentation.
I managed to fix it finally. I will explain how I did it incase anyone runs into the same problem.
I implemented another array myVisibleIncomeArray.
In viewDidLoad() I called a function which does the following:
for inc in myIncomeArray {
if self.monthLabel.text == "All" {
self.myVisibleIncomeArray.append(inc)
totalSum += inc.money
print("Added to myVisible")
}
}
Then I reloadData() and use myVisibleIncomeArray for the other functions.
Not sure if it was the smartest fix, but it's a fix nonetheless.
i'm trying to delete a cell from UITableView in swift, i follow this tutorial: http://www.ioscreator.com/tutorials/delete-rows-table-view-ios8-swift
the problem is my UITableView has many section, so i can't delete the cell the way like the tutorial.
any one know how to delete cell form table with multiple section?
thanks.
You cannot delete multiple cells at once with the method described in the tutorial. That will only work for single cell. If you select multiple cells and use button, for example, to trigger delete action, your code could look something like this:
if let indexPaths = tableView.indexPathsForSelectedRows() as? [NSIndexPath] {
for indexPath in indexPaths {
// one by one remove items from your datasource
}
tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic)
}
Instead of using numbers[row] in the example you can use numbers[section][row]. So the code will look like:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numbers[section].count
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
numbers[indexPath.section].removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
Neither of answers worked for me. Swift Array indexes are updated upon removal hence for-in loop for indexes from .indexPathsForSelectedRows() provided unexpected results i.e. wrong data/tables removed and eventually crash with index outside of array bounds error. Found good (but really outdated) Objective-C iOS Developer Library example. But it utilised NSMutableArray removeObjectsAtIndexes method, not present with Swift Array. Anyway a good deal of useful tricks in there so worth take a look.
The method which work for me is part from that example but instead of removeObjectsAtIndexes do-while is used to remove rows one by one until all selected rows are removed. The method below called by UIAlertAction similar to Apple example.
func deleteSelectedRows() {
// Unwrap indexPaths to check if rows are selected
if let _ = tableView.indexPathsForSelectedRows() {
// Do while all selected rows are deleted
do {
if let indexPath = tableView.indexPathForSelectedRow(){
//remove from table view data source and table view
self.dataSource.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
} while tableView.indexPathsForSelectedRows() != nil
}else{
// Delete everything, delete the objects from data model.
self.dataSource.removeAll(keepCapacity: false)
// Tell the tableView that we deleted the objects.
// Because we are deleting all the rows, just reload the current table section
self.tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Automatic)
}
// Exit editing mode after the deletion.
self.tableView.setEditing(false, animated: true)
}
Edit: While do-while did it trick for small example I've been working with (jus starting with swift) It's not efficient. Either extending Array or make data source Equatable and use find() or .filter is preferable.But I'm sure there should be a simpler way. The one I'm using now is described on link below:
http://www.rockhoppertech.com/blog/swift-remove-array-item/
func == (lhs: myDataSource, rhs: myDataSource) -> Bool {
if lhs.data == rhs.data &&
lhs.otherData == rhs.otherData {
return true
}
return false
}
struct myDataSource: Equatable {
let data: String
let otherData: String
}
And then:
if let selectedRows = tableView.indexPathsForSelectedRows(){
var objectsToDelete = [myDataSource]()
for selectedRow in selectedRows {
objectsToDelete.append(myDataSource[selectedRow.row])
}
for object in objectsToDelete {
if let index = find(myDataSource, object){
myDataSource.removeAtIndex(index)
}
}
}
tableView.deleteRowsAtIndexPaths([selectedRows], withRowAnimation: .Automatic)
try to this. this works fine.
But don't forget to this before.
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
{
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
{
if editingStyle == .Delete
{
arrayOfnames.removeAtIndex(indexPath.row)
self.tableViewww.reloadData()
}
}