使用领域对象滚动到 UITableView 中最新插入的行
Scroll to the latest inserted row in UITableView using Realm Objects
我有以下代码运行良好,它从 Realm
中名为 groceryList
的列表中获取项目列表,并按基于降序的顺序将它们显示在 UITableView
上在产品名称上。我想做的是滚动到 table 中最新插入的 row/item,现在当插入新项目时,用户可能看不到它,因为这些项目是按字母顺序重新排序的,并且table视图中可能看不到最新项目。
如何滚动到 UITableView 中最新插入的 row/item?
领域对象:
class Item:Object{
@objc dynamic var productName:String = ""
@objc dynamic var isItemActive = true
@objc dynamic var createdAt = NSDate()
}
class ItemList: Object {
@objc dynamic var listName = ""
@objc dynamic var createdAt = NSDate()
let items = List<Item>()
}
UITableView:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
var allItems : Results<Item>!
var groceryList : ItemList!
override func viewDidLoad() {
super.viewDidLoad()
groceryList = realm.objects(ItemList.self).filter("listName = %@", "groceryList").first
updateResultsList()
}
func updateResultsList(){
if let list = groceryList{
allItems = activeList.items.sorted(byKeyPath: "productName", ascending: false)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! CustomCell
let data = allItems[indexPath.row]
cell.displayProductName.text = data.productName
return cell
}
}
添加以下代码作为表格视图的扩展。
extension UITableView {
func scrollToBottom() {
let sections = numberOfSections-1
if sections >= 0 {
let rows = numberOfRows(inSection: sections)-1
if rows >= 0 {
let indexPath = IndexPath(row: rows, section: sections)
DispatchQueue.main.async { [weak self] in
self?.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
}
}
}
现在只需在您的方法中使用它:
func updateResultsList(){
if let list = groceryList{
allItems = activeList.items.sorted(byKeyPath: "productName", ascending: false
yourTableView.scrollToBottom()
}
}
只要在你想要的地方使用这个方法,它应该向下滚动。
yourTableView.scrollToBottom()
您可以使用 Realm
通知来了解数据源 Results
何时被修改,然后从那里更新您的 table 视图并进行滚动。
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var allItems: Results<Item>!
var groceryList: ItemList!
var notificationToken: NotificationToken? = nil
deinit {
notificationToken?.invalidate()
}
override func viewDidLoad() {
super.viewDidLoad()
groceryList = realm.objects(ItemList.self).filter("listName = %@", "groceryList").first
updateResultsList()
observeGroceryList
}
func updateResultsList(){
if let list = groceryList {
allItems = activeList.items.sorted(byKeyPath: "productName", ascending: false)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! CustomCell
let data = allItems[indexPath.row]
cell.displayProductName.text = data.productName
return cell
}
func observeGroceryList() {
notificationToken = allItems.observe { [weak self] (changes: RealmCollectionChange) in
switch changes {
case .initial:
self?.tableView.reloadData()
case .update(_, let deletions, let insertions, let modifications):
// Query results have changed, so apply them to the UITableView
self?.tableView.beginUpdates()
self?.tableView.insertRows(at: insertions.map({ IndexPath(row: [=10=], section: 0) }),
with: .automatic)
self?.tableView.deleteRows(at: deletions.map({ IndexPath(row: [=10=], section: 0)}),
with: .automatic)
self?.tableView.reloadRows(at: modifications.map({ IndexPath(row: [=10=], section: 0) }),
with: .automatic)
self?.tableView.endUpdates()
if let lastInsertedRow = insertions.last {
self?.tableView.scrollToRow(at: insertions.last, at: .none, animated: true)
}
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
print("\(error)")
}
}
}
}
我有以下代码运行良好,它从 Realm
中名为 groceryList
的列表中获取项目列表,并按基于降序的顺序将它们显示在 UITableView
上在产品名称上。我想做的是滚动到 table 中最新插入的 row/item,现在当插入新项目时,用户可能看不到它,因为这些项目是按字母顺序重新排序的,并且table视图中可能看不到最新项目。
如何滚动到 UITableView 中最新插入的 row/item?
领域对象:
class Item:Object{
@objc dynamic var productName:String = ""
@objc dynamic var isItemActive = true
@objc dynamic var createdAt = NSDate()
}
class ItemList: Object {
@objc dynamic var listName = ""
@objc dynamic var createdAt = NSDate()
let items = List<Item>()
}
UITableView:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
var allItems : Results<Item>!
var groceryList : ItemList!
override func viewDidLoad() {
super.viewDidLoad()
groceryList = realm.objects(ItemList.self).filter("listName = %@", "groceryList").first
updateResultsList()
}
func updateResultsList(){
if let list = groceryList{
allItems = activeList.items.sorted(byKeyPath: "productName", ascending: false)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! CustomCell
let data = allItems[indexPath.row]
cell.displayProductName.text = data.productName
return cell
}
}
添加以下代码作为表格视图的扩展。
extension UITableView {
func scrollToBottom() {
let sections = numberOfSections-1
if sections >= 0 {
let rows = numberOfRows(inSection: sections)-1
if rows >= 0 {
let indexPath = IndexPath(row: rows, section: sections)
DispatchQueue.main.async { [weak self] in
self?.scrollToRow(at: indexPath, at: .bottom, animated: true)
}
}
}
}
}
现在只需在您的方法中使用它:
func updateResultsList(){
if let list = groceryList{
allItems = activeList.items.sorted(byKeyPath: "productName", ascending: false
yourTableView.scrollToBottom()
}
}
只要在你想要的地方使用这个方法,它应该向下滚动。
yourTableView.scrollToBottom()
您可以使用 Realm
通知来了解数据源 Results
何时被修改,然后从那里更新您的 table 视图并进行滚动。
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var allItems: Results<Item>!
var groceryList: ItemList!
var notificationToken: NotificationToken? = nil
deinit {
notificationToken?.invalidate()
}
override func viewDidLoad() {
super.viewDidLoad()
groceryList = realm.objects(ItemList.self).filter("listName = %@", "groceryList").first
updateResultsList()
observeGroceryList
}
func updateResultsList(){
if let list = groceryList {
allItems = activeList.items.sorted(byKeyPath: "productName", ascending: false)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath) as! CustomCell
let data = allItems[indexPath.row]
cell.displayProductName.text = data.productName
return cell
}
func observeGroceryList() {
notificationToken = allItems.observe { [weak self] (changes: RealmCollectionChange) in
switch changes {
case .initial:
self?.tableView.reloadData()
case .update(_, let deletions, let insertions, let modifications):
// Query results have changed, so apply them to the UITableView
self?.tableView.beginUpdates()
self?.tableView.insertRows(at: insertions.map({ IndexPath(row: [=10=], section: 0) }),
with: .automatic)
self?.tableView.deleteRows(at: deletions.map({ IndexPath(row: [=10=], section: 0)}),
with: .automatic)
self?.tableView.reloadRows(at: modifications.map({ IndexPath(row: [=10=], section: 0) }),
with: .automatic)
self?.tableView.endUpdates()
if let lastInsertedRow = insertions.last {
self?.tableView.scrollToRow(at: insertions.last, at: .none, animated: true)
}
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
print("\(error)")
}
}
}
}