回答:
cellForRowAtIndexPath:
メソッドのどこにいるかのチェックを追加することでそれを行うことができます。この方法は理解しやすく、実装も簡単です。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Classic start method
static NSString *cellIdentifier = @"MyCell";
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MainMenuCellIdentifier];
}
MyData *data = [self.dataArray objectAtIndex:indexPath.row];
// Do your cell customisation
// cell.titleLabel.text = data.title;
BOOL lastItemReached = [data isEqual:[[self.dataArray] lastObject]];
if (!lastItemReached && indexPath.row == [self.dataArray count] - 1)
{
[self launchReload];
}
}
編集:再帰呼び出しを防ぐために最後の項目にチェックを追加しました。最後の項目に到達したかどうかを定義するメソッドを実装する必要があります。
EDIT2:lastItemReachedの説明
launchReload
メソッドの責任です(たとえば、一度に1つの非同期リロードアクションのみ)
if !lastItemReached && indexPath.row == dataArray!.hits.count - 1 {
self.launchReload
方法は何ですか?
方法1:下にスクロールしました
ペドロロマンの回答のSwiftバージョンは次のとおりです。ユーザーがスクロールを停止すると、下部に達したかどうかを確認します。
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// UITableView only moves in one direction, y axis
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
// Change 10.0 to adjust the distance from bottom
if maximumOffset - currentOffset <= 10.0 {
self.loadMore()
}
}
方法2:最後の行に達した
そして、これがshinyuXの回答の Swiftバージョンです。ユーザーが最後の行に到達したかどうかを確認します。
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// set up cell
// ...
// Check if the last row number is the same as the last current data element
if indexPath.row == self.dataArray.count - 1 {
self.loadMore()
}
}
loadMore()
メソッドの例データのバッチをフェッチするために、これら3つのクラス変数を設定しました。
// number of items to be fetched each time (i.e., database LIMIT)
let itemsPerBatch = 50
// Where to start fetching items (database OFFSET)
var offset = 0
// a flag for when all database items have already been loaded
var reachedEndOfItems = false
これは、データベースからテーブルビューにさらに項目をロードする関数です。
func loadMore() {
// don't bother doing another db query if already have everything
guard !self.reachedEndOfItems else {
return
}
// query the db on a background thread
DispatchQueue.global(qos: .background).async {
// determine the range of data items to fetch
var thisBatchOfItems: [MyObjects]?
let start = self.offset
let end = self.offset + self.itemsPerBatch
// query the database
do {
// SQLite.swift wrapper
thisBatchOfItems = try MyDataHelper.findRange(start..<end)
} catch _ {
print("query failed")
}
// update UITableView with new batch of items on main thread after query finishes
DispatchQueue.main.async {
if let newItems = thisBatchOfItems {
// append the new items to the data source for the table view
self.myObjectArray.appendContentsOf(newItems)
// reload the table view
self.tableView.reloadData()
// check if this was the last of the data
if newItems.count < self.itemsPerBatch {
self.reachedEndOfItems = true
print("reached end of data. Batch count: \(newItems.count)")
}
// reset the offset for the next data query
self.offset += self.itemsPerBatch
}
}
}
}
willDisplayCell
どのセルが読み込まれるかどうかを確認するメソッドを使用する方が良いです。電流indexPath.row
が最後になると、さらに多くのセルをロードできます。下にスクロールすると、より多くのセルが読み込まれます。
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// check if indexPath.row is last row
// Perform operation to load new Cell's.
}
UIScrollView / UICollectionView / UITableViewと連携
import UIKit
class LoadMoreActivityIndicator {
private let spacingFromLastCell: CGFloat
private let spacingFromLastCellWhenLoadMoreActionStart: CGFloat
private weak var activityIndicatorView: UIActivityIndicatorView?
private weak var scrollView: UIScrollView?
private var defaultY: CGFloat {
guard let height = scrollView?.contentSize.height else { return 0.0 }
return height + spacingFromLastCell
}
deinit { activityIndicatorView?.removeFromSuperview() }
init (scrollView: UIScrollView, spacingFromLastCell: CGFloat, spacingFromLastCellWhenLoadMoreActionStart: CGFloat) {
self.scrollView = scrollView
self.spacingFromLastCell = spacingFromLastCell
self.spacingFromLastCellWhenLoadMoreActionStart = spacingFromLastCellWhenLoadMoreActionStart
let size:CGFloat = 40
let frame = CGRect(x: (scrollView.frame.width-size)/2, y: scrollView.contentSize.height + spacingFromLastCell, width: size, height: size)
let activityIndicatorView = UIActivityIndicatorView(frame: frame)
activityIndicatorView.color = .black
activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
activityIndicatorView.hidesWhenStopped = true
scrollView.addSubview(activityIndicatorView)
self.activityIndicatorView = activityIndicatorView
}
private var isHidden: Bool {
guard let scrollView = scrollView else { return true }
return scrollView.contentSize.height < scrollView.frame.size.height
}
func start(closure: (() -> Void)?) {
guard let scrollView = scrollView, let activityIndicatorView = activityIndicatorView else { return }
let offsetY = scrollView.contentOffset.y
activityIndicatorView.isHidden = isHidden
if !isHidden && offsetY >= 0 {
let contentDelta = scrollView.contentSize.height - scrollView.frame.size.height
let offsetDelta = offsetY - contentDelta
let newY = defaultY-offsetDelta
if newY < scrollView.frame.height {
activityIndicatorView.frame.origin.y = newY
} else {
if activityIndicatorView.frame.origin.y != defaultY {
activityIndicatorView.frame.origin.y = defaultY
}
}
if !activityIndicatorView.isAnimating {
if offsetY > contentDelta && offsetDelta >= spacingFromLastCellWhenLoadMoreActionStart && !activityIndicatorView.isAnimating {
activityIndicatorView.startAnimating()
closure?()
}
}
if scrollView.isDecelerating {
if activityIndicatorView.isAnimating && scrollView.contentInset.bottom == 0 {
UIView.animate(withDuration: 0.3) { [weak self] in
if let bottom = self?.spacingFromLastCellWhenLoadMoreActionStart {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: bottom, right: 0)
}
}
}
}
}
}
func stop(completion: (() -> Void)? = nil) {
guard let scrollView = scrollView , let activityIndicatorView = activityIndicatorView else { return }
let contentDelta = scrollView.contentSize.height - scrollView.frame.size.height
let offsetDelta = scrollView.contentOffset.y - contentDelta
if offsetDelta >= 0 {
UIView.animate(withDuration: 0.3, animations: {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}) { _ in completion?() }
} else {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
completion?()
}
activityIndicatorView.stopAnimating()
}
}
初期化
activityIndicator = LoadMoreActivityIndicator(scrollView: tableView, spacingFromLastCell: 10, spacingFromLastCellWhenLoadMoreActionStart: 60)
取り扱い
extension ViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
activityIndicator.start {
DispatchQueue.global(qos: .utility).async {
sleep(3)
DispatchQueue.main.async { [weak self] in
self?.activityIndicator.stop()
}
}
}
}
}
ソリューションコードを貼り付けることを忘れないでください。
import UIKit
class ViewController: UIViewController {
fileprivate var activityIndicator: LoadMoreActivityIndicator!
override func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView(frame: view.frame)
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.dataSource = self
tableView.delegate = self
tableView.tableFooterView = UIView()
activityIndicator = LoadMoreActivityIndicator(scrollView: tableView, spacingFromLastCell: 10, spacingFromLastCellWhenLoadMoreActionStart: 60)
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "\(indexPath)"
return cell
}
}
extension ViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
activityIndicator.start {
DispatchQueue.global(qos: .utility).async {
for i in 0..<3 {
print("!!!!!!!!! \(i)")
sleep(1)
}
DispatchQueue.main.async { [weak self] in
self?.activityIndicator.stop()
}
}
}
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger lastSectionIndex = [tableView numberOfSections] - 1;
NSInteger lastRowIndex = [tableView numberOfRowsInSection:lastSectionIndex] - 1;
if ((indexPath.section == lastSectionIndex) && (indexPath.row == lastRowIndex)) {
// This is the last cell
[self loadMore];
}
}
あなたは、コアデータを使用している場合とNSFetchedResultsController
、その後、loadMore
以下のようになります。
// Load more
- (void)loadMore {
[self.fetchedResultsController.fetchRequest setFetchLimit:newFetchLimit];
[NSFetchedResultsController deleteCacheWithName:@"cache name"];
NSError *error;
if (![self.fetchedResultsController performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
[self.tableView reloadData];
}
私はstackoverflowで見つけた1つのソリューションを実装しましたが、それはうまく機能しますが、shinyuXのソリューションは非常に簡単に実装でき、私の提案に対してうまく機能すると思います。誰かが別のソリューションを必要とする場合は、以下のソリューションを使用できます。
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
// UITableView only moves in one direction, y axis
CGFloat currentOffset = scrollView.contentOffset.y;
CGFloat maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
//NSInteger result = maximumOffset - currentOffset;
// Change 10.0 to adjust the distance from bottom
if (maximumOffset - currentOffset <= 10.0) {
[self loadOneMorePage];
//[self methodThatAddsDataAndReloadsTableView];
}
}
LoadmoreのGenetic UITableView拡張機能。
このUITableView + Extensionを新しいファイルに追加します
extension UITableView{
func indicatorView() -> UIActivityIndicatorView{
var activityIndicatorView = UIActivityIndicatorView()
if self.tableFooterView == nil{
let indicatorFrame = CGRect(x: 0, y: 0, width: self.bounds.width, height: 40)
activityIndicatorView = UIActivityIndicatorView(frame: indicatorFrame)
activityIndicatorView.isHidden = false
activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
activityIndicatorView.isHidden = true
self.tableFooterView = activityIndicatorView
return activityIndicatorView
}else{
return activityIndicatorView
}
}
func addLoading(_ indexPath:IndexPath, closure: @escaping (() -> Void)){
indicatorView().startAnimating()
if let lastVisibleIndexPath = self.indexPathsForVisibleRows?.last {
if indexPath == lastVisibleIndexPath && indexPath.row == self.numberOfRows(inSection: 0) - 1 {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
closure()
}
}
}
indicatorView().isHidden = false
}
func stopLoading(){
indicatorView().stopAnimating()
indicatorView().isHidden = true
}
}
次に、UITableViewDelegateメソッドwillDisplay Cellに次のコード行をViewControllerに追加し、tableView.delegate = selfを確認します
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// need to pass your indexpath then it showing your indicator at bottom
tableView.addLoading(indexPath) {
// add your code here
// append Your array and reload your tableview
tableView.stopLoading() // stop your indicator
}
}
それだけです。これが役に立てば幸いです。ありがとうございました
クエリで制限とオフセットを使用し、テーブルビューにそのコンテンツを入力します。ユーザーが下にスクロールすると、次のオフセットをロードします。
にtableView:willDisplayCell:forRowAtIndexPath:
メソッドを実装し、UITableViewDelegate
それが最後の行かどうかを確認します
以下のリンクはサンプルコードを提供します。#Swift3
ユーザーは、サーバーからより多くのデータをフェッチするために、最後のテーブルビューセル(少なくとも2セルの高さ)をプルアップする必要があります。
最後のセルと同様に、プロセスセルもロードプロセスを表示します。
そのSwift3
使用するもう1つのオプション(Swift 3およびiOS 10以降):
class DocumentEventsTableViewController: UITableViewController, UITableViewDataSourcePrefetching {
var currentPage: Int = 1
let pageSize: Int = 10 // num of items in one page
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.prefetchDataSource = self
}
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
let upcomingRows = indexPaths.map { $0.row }
if let maxIndex = upcomingRows.max() {
let nextPage: Int = Int(ceil(Double(maxIndex) / Double(pageSize))) + 1
if nextPage > currentPage {
// Your function, which attempts to load respective page from the local database
loadLocalData(page: nextPage)
// Your function, which makes a network request to fetch the respective page of data from the network
startLoadingDataFromNetwork(page: nextPage)
currentPage = nextPage
}
}
}
}
かなり小さいページ(〜10アイテム)の場合、テーブルがいくつかのアイテムをスクロールできるようになるまでnextPageが1〜2程度になるため、ページ1と2のデータを手動で追加することができます。しかし、それはすべての次のページでうまく機能します。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (news.count == 0) {
return 0;
} else {
return news.count + 1 ;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@try {
uint position = (uint) (indexPath.row);
NSUInteger row = [indexPath row];
NSUInteger count = [news count];
//show Load More
if (row == count) {
UITableViewCell *cell = nil;
static NSString *LoadMoreId = @"LoadMore";
cell = [tableView dequeueReusableCellWithIdentifier:LoadMoreId];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:LoadMoreId];
}
if (!hasMoreLoad) {
cell.hidden = true;
} else {
cell.textLabel.text = @"Load more items...";
cell.textLabel.textColor = [UIColor blueColor];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
NSLog(@"Load more");
if (!isMoreLoaded) {
isMoreLoaded = true;
[self performSelector:@selector(loadMoreNews) withObject:nil afterDelay:0.1];
}
}
return cell;
} else {
NewsRow *cell = nil;
NewsObject *newsObject = news[position];
static NSString *CellIdentifier = @"NewsRow";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = topLevelObjects[0];
// Configure the cell...
}
cell.title.text = newsObject.title;
return cell;
}
}
@catch (NSException *exception) {
NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
}
return nil;
}
この投稿に関する非常に良い説明。
http://useyourloaf.com/blog/2010/10/02/dynamically-loading-new-rows-into-a-table.html
単純なのは、最後の行を追加して非表示にし、テーブルの行が最後の行にヒットしたときに、行を表示してより多くのアイテムをロードすることです。
ios UITableViewDataSourcePrefetchingを確認する必要があります。
class ViewController: UIViewController {
@IBOutlet weak var mytableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
mytableview.prefetchDataSource = self
}
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
print("prefetchdRowsAtIndexpath \(indexPaths)")
}
func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
print("cancelPrefetchingForRowsAtIndexpath \(indexPaths)")
}
}
APIからロードする場合、Xcode 10、Swift 4.2で機能します。
1-新しいSwiftファイルを作成し、次のようにします。
//
// apiTVCController.swift
// ApiTestingTableView
//
// Created by Hooma7n on 4/7/19.
// Copyright © 2019 Hooma7n. All rights reserved.
//
import Foundation
import Alamofire
class apiget {
var tableData : [Datum] = []
var loadin : [Datum] = []
var testfortotal : Int?
func getfromapi(completionHandler : ((_ isSucess : Bool) -> Void)?) {
let url = "https://reqres.in/api/users?page=1"
Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.responseJSON(completionHandler : { response in
switch response.result {
case .success(let data):
guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: JSONSerialization.WritingOptions.prettyPrinted) else {return}
let decoder = JSONDecoder()
guard let result = try? decoder.decode(Welcome.self, from: jsonData) else {return}
self.tableData = result.data ?? []
self.testfortotal = result.total ?? 0
completionHandler?(true)
// print(result)
case .failure(let error):
print(error)
}
})
}
var pagecounter : Int = 2
func loadmore(completionHandler : ((_ isSucess : Bool) -> Void)?){
let url = "https://reqres.in/api/users?page=\(pagecounter)"
Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.responseJSON(completionHandler : { response in
switch response.result {
case .success(let data):
guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: JSONSerialization.WritingOptions.prettyPrinted) else {return}
let decoder = JSONDecoder()
guard let myresult = try? decoder.decode(Welcome.self, from: jsonData) else {return}
self.loadin = myresult.data ?? []
self.tableData.append(contentsOf: myresult.data ?? [])
completionHandler?(true)
print(self.pagecounter)
self.pagecounter += 1
// print(myresult)
case .failure(let error):
print(error)
}
})
}
}
extension apiget {
struct Welcome: Codable {
let page, perPage, total, totalPages: Int?
var data: [Datum]?
enum CodingKeys: String, CodingKey {
case page
case perPage = "per_page"
case total
case totalPages = "total_pages"
case data
}
}
struct Datum: Codable {
let id: Int?
let firstName, lastName: String?
let avatar: String?
enum CodingKeys: String, CodingKey {
case id
case firstName = "first_name"
case lastName = "last_name"
case avatar
}
}
}
2- ViewControllerファイル(tableView Controller)内:
//
// apiTVC.swift
// ApiTestingTableView
//
// Created by Hooma7n on 4/7/19.
// Copyright © 2019 Hooma7n. All rights reserved.
//
import UIKit
import Alamofire
class apiTVC: UITableViewController {
var datamodel = apiget()
override func viewDidLoad() {
super.viewDidLoad()
datamodel.getfromapi(completionHandler: {finish in
if finish {self.tableView.reloadData()
}
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datamodel.tableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! apiTableViewCell
cell.firstNameLabel.text = datamodel.tableData[indexPath.row].firstName
cell.lastNameLabel.text = datamodel.tableData[indexPath.row].lastName
cell.dateLabel.text = "\(datamodel.tableData[indexPath.row].id ?? 0)"
cell.profileImageView.loadImage(fromURL: datamodel.tableData[indexPath.row].avatar ?? "")
return cell
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let lastElement = datamodel.tableData.count - 1
let total = datamodel.testfortotal ?? 12
if indexPath.row == lastElement && datamodel.tableData.count < total{
datamodel.loadmore(completionHandler: {finish in
if finish {
self.tableView.reloadData()
}})
}
}
}
viewController set delegateでtableViewを使用する場合、viewDidLoad でデータソース self。
このアプローチを共有したいだけです:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSLog(@"%@", [[YourTableView indexPathsForVisibleRows] lastObject]);
[self estimatedTotalData];
}
- (void)estimatedTotalData
{
long currentRow = ((NSIndexPath *)[[YourTableView indexPathsForVisibleRows] lastObject]).row;
long estimateDataCount = 25;
while (currentRow > estimateDataCount)
{
estimateDataCount+=25;
}
dataLimit = estimateDataCount;
if (dataLimit == currentRow+1)
{
dataLimit+=25;
}
NSLog(@"dataLimit :%ld", dataLimit);
[self requestForData];
// this answers the question..
//
if(YourDataSource.count-1 == currentRow)
{
NSLog(@"LAST ROW"); //loadMore data
}
}
NSLog(...);
出力は次のようになります。
<NSIndexPath: 0xc0000000002e0016> {length = 2, path = 0 - 92}
dataLimit :100
<NSIndexPath: 0xc000000000298016> {length = 2, path = 0 - 83}
dataLimit :100
<NSIndexPath: 0xc000000000278016> {length = 2, path = 0 - 79}
dataLimit :100
<NSIndexPath: 0xc000000000238016> {length = 2, path = 0 - 71}
dataLimit :75
<NSIndexPath: 0xc0000000001d8016> {length = 2, path = 0 - 59}
dataLimit :75
<NSIndexPath: 0xc0000000001c0016> {length = 2, path = 0 - 56}
dataLimit :75
<NSIndexPath: 0xc000000000138016> {length = 2, path = 0 - 39}
dataLimit :50
<NSIndexPath: 0xc000000000120016> {length = 2, path = 0 - 36}
dataLimit :50
<NSIndexPath: 0xc000000000008016> {length = 2, path = 0 - 1}
dataLimit :25
<NSIndexPath: 0xc000000000008016> {length = 2, path = 0 - 1}
dataLimit :25
これは、ローカルに保存されているデータを表示するのに適しています。最初にdataLimitを25に宣言します。これは、uitableviewが(最初は)0〜24になることを意味します。
ユーザーが一番下までスクロールし、最後のセルが表示dataLimit
されている場合、25が追加されます...
注:これは、UITableViewデータページングに似ています。
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger sectionsAmount = [tableView numberOfSections];
NSInteger rowsAmount = [tableView numberOfRowsInSection:[indexPath section]];
if ([indexPath section] == sectionsAmount - 1 && [indexPath row] == rowsAmount - 1) {
//get last row
if (!isSearchActive && !isFilterSearchActive) {
if (totalRecords % 8 == 0) {
int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[yourTableView beginUpdates];
[yourTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[yourTableView endUpdates];
});
}
}
}
}
この問題を解決する最良の方法は、テーブルの下部にセルを追加することです。このセルはインジケーターを保持します。
迅速にこれを追加する必要があります:
以下のコードを見てください:
import UIKit
class LoadingCell: UITableViewCell {
@IBOutlet weak var indicator: UIActivityIndicatorView!
}
テーブルビューの場合:numOfRows:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourArray.count + 1
}
cellForRawAt indexPath:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == users.count {
// need to change
let loading = Bundle.main.loadNibNamed("LoadingCell", owner: LoadingCell.self , options: nil)?.first as! LoadingCell
return loading
}
let yourCell = tableView.dequeueReusableCell(withIdentifier: "cellCustomizing", for: indexPath) as! UITableViewCell
return yourCell
}
ローディングセルがnibファイルから作成されていることに気付いた場合。このビデオは私が何をしたかを説明します。
let threshold = 100.0 // threshold from bottom of tableView
var isLoadingMore = false // flag
func scrollViewDidScroll(scrollView: UIScrollView) {
let contentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if !isLoadingMore && (maximumOffset - contentOffset <= threshold) {
// Get more data - API call
self.isLoadingMore = true
// Update UI
dispatch_async(dispatch_get_main_queue()) {
tableView.reloadData()
self.isLoadingMore = false
}
}
}
Xcode 10.1の場合、Swift 4.2
このビデオは素晴らしいチュートリアルのようです!
スターター/完全なプロジェクト:https : //github.com/RobCanton/Swift-Infinite-Scrolling-Example
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableView:UITableView!
var fetchingMore = false
var items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
initTableView()
}
func initTableView() {
tableView = UITableView(frame: view.bounds, style: .plain)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "tableCell")
tableView.delegate = self
tableView.dataSource = self
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
let layoutGuide = view.safeAreaLayoutGuide
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
cell.textLabel?.text = "Item \(items[indexPath.row])"
return cell
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
if offsetY > contentHeight - scrollView.frame.height * 4 {
if !fetchingMore {
beginBatchFetch()
}
}
}
func beginBatchFetch() {
fetchingMore = true
print("Call API here..")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.50, execute: {
print("Consider this as API response.")
let newItems = (self.items.count...self.items.count + 12).map { index in index }
self.items.append(contentsOf: newItems)
self.fetchingMore = false
self.tableView.reloadData()
})
}
}