iOS UITableView scrolling insets while filtering - ios

I have some problem with UITableView scrolling. This is my simple screen where I have UITextField and UITableView with cells. When user type something in UITextField app filters list of items and reloads UITableView. And it is working as expected.
On the right screen you can see how UITableView looks when I scroll. Cells go under UITextField.
Let's assume I scrolled some cell and If I start to type something in UITextField I got list of filtered cells but some of them are under UITextField and I can't scroll them down.

By default the table's scroll offset doesn't change when you reload the table with new set of row data. You need to scroll back to top after reloading the table :
self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0),
at: .top,
animated: true)
and if you don't have a default place-holder cell to represent "No Matching Results" when there are no results and thus no cells to represent at Index (0,0) then add following condition before the above code to safeguard a crash:
guard cellResults.count > 0 else { return }

First of all your UITextField contained on tableview header view? UITableView need scrolling with table or not?
If your need always show first cell when user input something in UITextField, i recommend it with RxSwift like this
textField
.rx.text
.orEmpty
.debounce(0.1, scheduler: MainScheduler.instance)
.distinctUntilChanged()
.subscribe(onNext: { [unowned self] query in
//TODO: Do something with you table, for example
// self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
// or update tableView.
})
.disposed(by: disposeBag)

Related

UiCollectionView jump on next cell when previous cell removed

I have custom layout with fullscreen cells. When removing cell from the left (it's not visible at the time), UICollectionView jumps to the next cell.
It's like current cell was at index 4 and when cell on the left removed the next cell has index 4 now and immediately scroll to the next cell.
Describing in 3 steps (A is cell that need to be fullscreen, x will be removed, o other cells, large letter is fullscreen):
ooooAoo
oooxAoo
oooaOo
But must keep this oooAoo
Here is my solution if it can help to anybody, did not found how to achieve desired offset natively, so just scrolling contentOffset to the desired position right after reloadData():
var currentCell: MyCollectionViewCell? {
return (visibleCells.sorted { $0.frame.width > $1.frame.width }.first) as? MyCollectionViewCell
}
//-----------------------------------------
//some model manipulating code, removing desired items here...
let currentList = currentCell?.parentList
reloadData()
if let list = currentList, let index = self.lists.firstIndex(of: list) {
self.scrollToItem(at: IndexPath(row: index, section: 0), at: .centeredHorizontally, animated: false)
}
currentCell is computed property, returns optional middle cell.
Detect which cell is the largest, because of custom flowlayout logic.
parentList is the model item, I can compare cell by it to make life
easier. I check which list was attached to the cell before
reloadData().

Issue while scrolling to UITableView bottom

I have a chat application ,where in when I press the send button the table gets reloaded with new row and I am calling scroll to bottom function to scroll to the newly added cell. The problem is that my textview text does not get emptied until the tableview scrolls to the bottom. Is there any other way to perform these actions so as to reduce the time delay?
Scroll to botton code:
self.tableView.reloadData()
let section: Int = numberOfSections(in: self.tableView) - 1
let item: Int = tableView(self.tableView, numberOfRowsInSection:section) - 1
let lastIndexPath = IndexPath(item: item, section: section)
self.tableView.scrollToRow(at: lastIndexPath, at: .bottom, animated: false)
When I remove the above code, the textview gets emptied instantly
The issue :
Make sure that you call reloadData() on the main thread. Doing it in a background thread will often cause graphical delays and may even crash the application.
Also, where do you empty the textview?

TableView not scrolling in iOS11

I am using the text fields inside the table view. On keyboard next button, the focus get shift to the next text field, this working fine still the iOS 10. but on iOS 11 table is not getting scrolled. Following scroll help me to scroll the table view.
Below method to scroll tableview up on which text field is selected, write this code in textfield delegate method.
func textFieldDidEndEditing(textField: UITextField) {
// calculate the nsindexpath based on the textfield which is selected
tableView.scrollToRow(at: IndexPath(row: textField.tag + 1, section: 0), at: UITableViewScrollPosition.top, animated: true)
}

How to scroll at the bottom with animated in UITableView swift 3

How to animate the footer view a table view when the UItableView reloads?
I am trying to append an element to the tableView and when the table view reloads the footer view should come with some animation. And also if the table view contents exceeds the screen size the footer view should stick with bottom of the screen. Here is my try:
tableView.beginUpdates()
self.familyAModelArray.append(self.childAModelArray)
tableView.endUpdates()
Note: Here i want to append an object to an array which is the content of the UITableView and reload the TableView. Thanks in advance!
To animate the insert action, you need to call insertRowsAtIndexPaths method with row animation.
After adding table cell elements to your array, you must calculate the index paths for the new cells to be displayed, and create an array of them, like this
let indexes = [IndexPath(row: 0, section: 0), IndexPath(row: 1, section: 0)]
Then simply call the following method to animate the insertion
tableView.beginUpdates()
tableView.insertRowsAtIndexPaths(indexes, withRowAnimation: .Fade)
tableView.endUpdates()
If you want the footer view to stick on the bottom of your screen, then it shouldn't be a footer view. it should be a custom UIView that is pinned to your view controller's view. Whenever you call a reloadData() on your tableView, you can likewise call a present/animate function on your new custom view that you pinned to the bottom & animate it on / off the screen.
I have solved this by using animation on UIView when the UITableView reloads after appending the rows.
UIView.transition(with: tableView, duration: 0.2, options: .curveEaseIn, animations: {self.tableView.reloadData()}, completion:{ (success) in
if success {
if self.familyAModelArray.count >= 3{
self.scrollToBottom()
}
}
})
And if length of my array is greater than 3 the footer view stick at the bottom by scrolling the UITableView to the top .
func scrollToBottom(){
DispatchQueue.global(qos: .background).async {
let indexPath = IndexPath(row: self.familyAModelArray.count-1, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
}
This solution has given a nice look for my table view.

Prevent uitableview from scrolling after removing last cell

I have a tableview (style - grouped) which contains more rows than can fit into its frame so you have to scroll to see the last row. When I delete the last row the tableview scrolls its content down so the new last row is at the bottom of the frame (kind of fill the empty space).
How can I prevent a UITableView from scrolling after I delete the last row in it? I want it to keep the empty space and do not scroll automatically.
I have tried to set content insets but it doesn't seem to prevent scrolling unfortunately.
EDIT: My code for removing the row:
func removeLastRow() {
let indexPath = IndexPath.init(row: self.messages.count - 1, section: 0)
self.messages.removeLast()
CATransaction.begin()
self.tableView.beginUpdates()
CATransaction.setCompletionBlock { () -> Void in
// do stuff, add new rows
}
self.tableView.deleteRows(at: [indexPath], with: .left)
self.tableView.endUpdates()
CATransaction.commit()
}
Retreive the cells size before deleting by calling tableView:heightForRowAt: and after deleting, set the vertical content offset of your table view manually to the current vertical content offset, plus the height of the cell.
let deletedCellHeight = tableView.heightForRowAt(indexPath)
Then:
tableView.contentOffset.x += deletedCellHeight

Resources