How to Insert New Cell into Uitableview in Swift

How to insert new cell into UITableView in Swift

Use beginUpdates and endUpdates to insert a new cell when the button clicked.

As @vadian said in comment, begin/endUpdates has no effect for a single insert/delete/move operation

First of all, append data in your tableview array

Yourarray.append([labeltext])  

Then update your table and insert a new row

// Update Table Data
tblname.beginUpdates()
tblname.insertRowsAtIndexPaths([
NSIndexPath(forRow: Yourarray.count-1, inSection: 0)], withRowAnimation: .Automatic)
tblname.endUpdates()

This inserts cell and doesn't need to reload the whole table but if you get any problem with this, you can also use tableview.reloadData()


Swift 3.0

tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: yourArray.count-1, section: 0)], with: .automatic)
tableView.endUpdates()

Objective-C

[self.tblname beginUpdates];
NSArray *arr = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:Yourarray.count-1 inSection:0]];
[self.tblname insertRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tblname endUpdates];

Inserting cell in specific section

First of all you need a data source array for the section for example

var songs = [String]()

Then you have to modify numberOfRowsInSection to return the number of songs for section 3. This method can be simplified anyway

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 3: return songs.count
default: return 1
}
}

Now you can add a new song to the array and insert the row

func insertNewSongCell() {
let insertionIndex = songs.count
songs.append("New Song")
let indexPath = IndexPath(row: insertionIndex, section: 3)
tableView.insertRows(at: [indexPath], with: .automatic)
}

beginUpdates and endUpdates have no effect in this case, you can omit the lines.

Insert row tableview with a button at last section

On click of "Add" button, You should not reload the the entire table view because it increases the processing time. Instead of that you can use of
beginUpdates and endUpdates for inserting new cell when button clicked.

Basic Approaches:

(1). On click of "Add", update your data-source for table-view.

dataSource.append(NewRecord)

(2). Insert the new cell:

 tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: dataSource.count-1, section: 0)], with: .automatic)
tableView.endUpdates()

Reviewing your Code:

func addButtonClicked(sender:UIButton) {
data.append("Guest 1")
.....
}

Your datasource is others on which the tableview is created and configured.
But on click of add button (addButtonClicked function), you are not updating the others data-source. Please verify it, except that your code seems good.

Swift: Insert new CustomTableViewCell row in TableView

You shouldn't update the model in cellForRowAt. That should only populate the cell's text field's initial value. If you want to find out about changes, you need to set up another mechanism for the cell to inform the view controller when the text field changes.

The basic idea is as follows:

  • Define protocol (which I called UserInputCellDelegate) by which cell can inform view controller of changes;

  • The cellForRowAt should merely update the text field in the cell with the value from the model (your datas). It also defines the view controller as the delegate for the cell (to receive the updates regarding changed values);

  • When the text field is updated (e.g. hooking up the IBOutlet for the "Editing did end"), the cell will inform the view controller of that change by calling the delegate method to inform the view controller of the changes.

  • When the view controller has its didUpdate called, it will update the model accordingly.

Thus:

class ViewController: UITableViewController {

var datas = [String]() // start with empty array

@IBAction func didTapAddButton(_ sender: Any) {
let indexPath = IndexPath(row: 0, section:0)
datas.insert("", at: indexPath.row) // inserting default value (I'm inserting ""; you can insert whatever you want)
tableView.insertRows(at: [indexPath], with: .automatic)
}

}

// MARK: - UITableViewDataSource

extension ViewController {

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datas.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) as! UserInputCell
cell.delegate = self
cell.usernameTextField.text = datas[indexPath.row]
return cell
}
}

// MARK: - UserInputCellDelegate

extension ViewController: UserInputCellDelegate {

func didUpdate(cell: UserInputCell, string: String?) {
if let indexPath = tableView.indexPath(for: cell) {
datas[indexPath.row] = string ?? "" // update `datas` with value user edited
}

// For giggles and grins, let's print the array, so we can see what it's doing.
// In production app, this `print` statement would be removed.

print("\(datas)")
}

}

And

protocol UserInputCellDelegate: class {                     // this is class protocol, to allow weak reference

/// When text field is updated, cell calls this delegate method to inform it of changes
/// to text field value.
///
/// - Parameters:
/// - cell: Cell containing text field that was updated
/// - string: String value entered.

func didUpdate(cell: UserInputCell, string: String?)

}

class UserInputCell: UITableViewCell, UITextFieldDelegate {

weak var delegate: UserInputCellDelegate? // note this is weak to avoid strong reference cycle

@IBOutlet weak var usernameTextField: UITextField!

// hooked up to "Editing did end" action for text field in IB

@IBAction func didEndEditing(_ sender: UITextField) {
delegate?.didUpdate(cell: self, string: sender.text)
}

}

Add and delete cell from table view in swift

The problem is in the way you create an indexPath for inserting a new row, fix it according to this:

@IBAction func addCardBtnTapped(_ sender: Any) {

numberOfCell += 1
// create indexPath from numberOfCell, not from allCellsText.count
let indexPath = IndexPath(row: numberOfCell - 1, section: 0)
flashCardTableView.beginUpdates()
flashCardTableView.insertRows(at: [indexPath], with: .automatic)
flashCardTableView.endUpdates()
view.endEditing(true)
}

The problem is in creating the IndexPath using IndexPath(row: allCellsText.count+1, section: 0). The insertions and deletions on tableView HAVE to be consistent with the dataSource - if you add a new row, the numberOfRowsInSection HAVE to increase by one, too. Now in your case you increment numberOfCell by one, as you are supposed to do, but then you try to add the new row at an indexPath determined by allCellsText.count+1. The problem is that the allCellsText.count is not consistent with numberOfCell variable (notice that you append a new string everytime textFieldDidEndEditing gets called).

EDIT

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allCellsTermText.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = flashCardTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FlashCardTableViewCell
// configure it with the backing data
cell.termTxt.text = allCellsTermText[indexPath.row]
cell.definitionTxt.text = allCellsDefinitionText[indexPath.row]

// now instead of this you will have to find a way how you will be
// able to determine the row which needs to be changed and change the model
// cell.termTxt.delegate = self
// cell.definitionTxt.delegate = self
return cell
}


func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 115
}

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

if editingStyle == .delete {
allCellsTermText.remove(at: indexPath.row)
allCellsDefinitionText.remove(at: indexPath.row)
flashCardTableView.deleteRows(at: [indexPath], with: .automatic)
}
}

func textFieldDidEndEditing(_ textField: UITextField) {
// you should not append here, this will add a new row, you have to UPDATE the proper text
// allCellsText.append(textField.text!)
}


@IBAction func addCardBtnTapped(_ sender: Any) {

// create a new row by appending new empty strings
allCellsTermText.append("")
allCellsDefinitionText.append("")

let indexPath = IndexPath(row: allCellsTermText.count - 1, section: 0)
flashCardTableView.insertRows(at: [indexPath], with: .automatic)
view.endEditing(true)
}

How to insert a new cell in between UITableViewCell in Swift

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
(...)
tableView.insertRows(at: [IndexPaths], with: .top)
}

Insert rows into TableView onto without changing scroll position

In your case, you do not need to make beginUpdates/endUpdates/insertRows for the tableView, just insert a new model and reload the tableView that enough.

You can resolve the problem like this:

// Calculate the distance of the tableView
// from the current content offset to the end of the content size
let distanceFromOffset = self.tableView.contentSize.height - self.tableView.contentOffset.y

// Insert new model into the list model at zero index
self.messages.insert(message, at: 0)

self.tableView.reloadData() // reload tableView

// Calculate new content offset after reload tableView
let offset = self.tableView.contentSize.height - distanceFromOffset

self.tableView.layoutIfNeeded()
// set new content offset for the tableview without animation
self.tableView.setContentOffset(CGPoint(x: 0, y: offset), animated: false)

Unable to insert new row to UITableView with dynamic number of Sections And Rows

As the error message tells you, you are trying to insert more rows, but what your array is telling you is that you need more sections. You should therefor use:

tableView.insertSections(sections: IndexSet, with: UITableViewRowAnimation)


Related Topics



Leave a reply



Submit