it-swarm.com.de

Swift tableView Paginierung

Ich habe Erfolg beim Arbeiten mit Tableview mit Json-Parsing-Codes. Aber es können noch 1000 weitere Elemente vorhanden sein. Ich weiß nicht, wie ich diese Codes unten machen kann. Für Objective-c habe ich viele Beispiele, aber für Swift fand ich kein funktionierendes Beispiel. Ich warte auf deine Hilfe. Ich denke, zu vielen Menschen wird geholfen. Vielen Dank ! 

import UIKit

class ViewController: UIViewController, UITableViewDataSource,UITableViewDelegate {

    let kSuccessTitle = "Congratulations"
    let kErrorTitle = "Connection error"
    let kNoticeTitle = "Notice"
    let kWarningTitle = "Warning"
    let kInfoTitle = "Info"
    let kSubtitle = "You've just displayed this awesome Pop Up View"


    @IBOutlet weak var myTableView: UITableView!
    @IBOutlet weak var myActivityIndicator: UIActivityIndicatorView!

    var privateList = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        loadItems()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


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




    internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {

       let cell:myCell = tableView.dequeueReusableCellWithIdentifier("myCell") as! myCell

        cell.titleLabel.text = privateList[indexPath.row]


        return cell
    }


    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

        if (editingStyle == UITableViewCellEditingStyle.Delete){

         print(indexPath.row)


            let alert = SCLAlertView()
            alert.addButton("Hayır"){ }
            alert.addButton("Evet") {

                self.myTableView.beginUpdates()

                 self.privateList.removeAtIndex(indexPath.row)
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Left)
                print("Silindi")

                self.myTableView.endUpdates()

                  self.loadItems()

            }
            alert.showSuccess(kSuccessTitle, subTitle: kSubtitle)

        }


    }





    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // the cells you would like the actions to appear needs to be editable
        return true
    }



    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {


        if(segue.identifier == "Detail") {

            let destinationView = segue.destinationViewController as! DetailViewController

            if let indexPath = myTableView.indexPathForCell(sender as! UITableViewCell) {

                destinationView.privateLista = privateList[indexPath.row]

            }
        }
    }



    internal func tableView(tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat
    {
        return 0.0
    }


    func loadItems()
    {
     loadItemsNow("privateList")

    }

    func loadItemsNow(listType:String){
        myActivityIndicator.startAnimating()
        let listUrlString =  "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString
        let myUrl = NSURL(string: listUrlString);
        let request = NSMutableURLRequest(URL:myUrl!);
        request.HTTPMethod = "GET";

        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in

            if error != nil {
                print(error!.localizedDescription)
                dispatch_async(dispatch_get_main_queue(),{
                    self.myActivityIndicator.stopAnimating()
                })

                return
            }


            do {

                let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray

                if let parseJSON = json {


                        self.privateList = parseJSON as! [String]

                }

            } catch {
                print(error)

            }

            dispatch_async(dispatch_get_main_queue(),{
                self.myActivityIndicator.stopAnimating()
                self.myTableView.reloadData()
            })


        }

        task.resume()
    }


}
38
SwiftDeveloper

Dafür müssen Sie auch serverseitig wechseln.

  1. Der Server akzeptiert fromIndex und batchSize in der API-URL als Abfrageparameter. 

    let listUrlString =  "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString + "&batchSize=" + batchSize + "&fromIndex=" + fromIndex
    
  2. In der Serverantwort gibt es einen zusätzlichen Schlüssel totalItems. Dies wird verwendet, um festzustellen, ob alle Artikel empfangen wurden oder nicht. Ein Array oder Elemente fromIndex bis batchSize Anzahl der Elemente.

In der App-Seite

  1. Zuerst wird loadItem() mit fromIndex = 0 und batchSize = 20 (zum Beispiel in viewDidLoad() oder viewWillAppear) aufgerufen. removeAll items aus privateList array bevor Sie loadItem() zum ersten Mal aufrufen

  2. Server gibt ein Array mit den ersten 20 Elementen und totalItems Gesamtzahl der Elemente auf dem Server zurück.

  3. Hängen Sie die 20 Elemente im privateList-Array an und laden Sie tableView erneut.

  4. Überprüfen Sie in der tableView:cellForRowAtIndexPath-Methode, ob die Zelle die letzte Zelle ist. Prüfen Sie, ob totalItems (Formularserver) größer als privateList.count ist. Das bedeutet, dass der Server mehr Elemente zum Laden enthält

    if indexPath.row == privateList.count - 1 { // last cell
        if totalItems > privateList.count { // more items to fetch
            loadItem() // increment `fromIndex` by 20 before server call
        }
    }
    

Frage:where is refresh ? will be scrolling ?

Aktualisieren Sie nach dem Anhängen neuer Elemente im Array, wenn die Serverantwort empfangen wurde. (Schritt 3)

Beim Scrollen wird tableView:cellForRowAtIndexPath für jede Zelle ausgelöst, wenn der Benutzer blättert. Der Code prüft, ob es sich um die letzte Zelle handelt, und holt die verbleibenden Elemente. (Schritt 4) 

Beispielprojekt hinzugefügt: 
https://github.com/rishi420/TableViewPaging

50

Der beste und effizienteste Weg ist die Verwendung von scrollviewDelegate in der Tabellenansicht Fügen Sie einfach UIScrollViewDelegate in Ihren viewControllerIn View Controller ein 

//For Pagination
var isDataLoading:Bool=false
var pageNo:Int=0
var limit:Int=20
var offset:Int=0 //pageNo*limit
var didEndReached:Bool=false
viewDidLoad(_){
tableview.delegate=self //To enable scrollviewdelegate
}

Überschreiben Sie zwei Methoden von diesem Delegierten

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {

        print("scrollViewWillBeginDragging")
        isDataLoading = false
    }



    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        print("scrollViewDidEndDecelerating")
    }
    //Pagination
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

            print("scrollViewDidEndDragging")
            if ((tableView.contentOffset.y + tableView.frame.size.height) >= tableView.contentSize.height)
            {
                if !isDataLoading{
                    isDataLoading = true
                    self.pageNo=self.pageNo+1
                    self.limit=self.limit+10
                    self.offset=self.limit * self.pageNo
                    loadCallLogData(offset: self.offset, limit: self.limit)

                }
            }


    }
10
Mahesh Giri

Swift 3,0 - 4 ...

Wenn Sie die Seitennummer in der API-Anforderung senden, ist dies der ideale Weg, um die Paginierung in Ihrer App zu implementieren.

1) deklarieren Sie die Variable als aktuelle Seite mit dem Anfangswert 0 und einem Bool, um zu prüfen, ob eine Liste mit dem Anfangswert falsch geladen wird 

var currentPage : Int = 0
var isLoadingList : Bool = false

2) Dies ist die Funktion, die das Listenbeispiel abruft:

 func getListFromServer(_ pageNumber: Int){
 self.isloadingList = false
 self.table.reloadData()
 } 

3) Diese Funktion erhöht die Seitennummer und ruft die API-Funktion auf 

 func loadMoreItemsForList(){
 currentPage += 1
 getListFromServer(currentPage)
 }

4) Dies ist die Methode, die aufgerufen wird, wenn die Bildlaufleiste scrollt

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (((scrollView.contentOffset.y + scrollView.frame.size.height) > scrollView.contentSize.height ) && ! isLoadingList){
        self. isLoadingList = true
        self. loadMoreItemsForList()
    }
}

P.S. Die Rolle "bool isLoadingList" soll verhindern, dass die Bildlaufansicht mehr Listen mit einem Zug am unteren Rand der Tabellenansicht erhält.

9
MhmdRizk

Dies ist jetzt etwas einfacher mit dem Hinzufügen eines neuen Protokolls in iOS10: UITableViewDataSourcePrefetching

https://developer.Apple.com/documentation/uikit/uitableviewdatasourceprefetching

7
Paul Robinson

Fügen Sie Ihrer Tabellenansicht einen weiteren Abschnitt hinzu. Lassen Sie diesen Abschnitt nur eine Zeile enthalten, die aus einer Zelle besteht, die einen Aktivitätsindikator enthält, um das Laden anzuzeigen.

internal func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
    return 2;
}

internal func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        if section == 0 {
            return privateList.count
        } else if section == 1 {    // this is going to be the last section with just 1 cell which will show the loading indicator
            return 1
        }
    }

internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
   if section == 0 {
       let cell:myCell = tableView.dequeueReusableCellWithIdentifier("myCell") as! myCell

        cell.titleLabel.text = privateList[indexPath.row]


        return cell
    } else if section == 1 { 
        //create the cell to show loading indicator
        ...

        //here we call loadItems so that there is an indication that something is loading and once loaded we relaod the tableview
        self.loadItems()
    }
}
2
Sumeet

Ich habe einen Ansatz mit willDisplayCell versucht. Beim Scrollen kommt es jedoch zu unerwünschten Stopps, was die Benutzerfreundlichkeit beeinträchtigt. Ich denke, ein besserer Weg ist, es in scrollViewDidEndDecelerating Delegate-Methode zu tun. Es ruft auf, wenn der Bildlauf beendet ist und nur dann neue Daten kommen. Der Benutzer sieht, dass es neue Inhalte gibt, und scrollt erneut, wenn er möchte. Ich habe die Antwort genommen hier aber anstelle von scrollViewDidEndDragging verwende ich scrollViewDidEndDecelerating. In meinem Fall sieht es einfach besser aus. Hier ist ein Code aus meinem Projekt.

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    guard scrollView == tableView,
        (scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height,
        !viewModel.isLastPeriodicsPage else { return }

    viewModel.paginatePeriodics(tableView.getLastIndexPath())
}

hier ist ein Beispielcode für die Sammlungsansicht:

var page = 0

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
    print("page Num:\(page)")
}

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath){
     if arrImagesData.count-1 == indexPath.row && arrImagesData.count%10 == 0{
        getMoreImages(page)
     }
}

func getMoreImages(page:Int){ 
   //hit api
   if api_success == true {
       if self.page == 0 {
          self.arrImagesData.removeAll()
       }
   self.arrImagesData.appendContentsOf(api_data)
   self.collectionImages.reloadData()
   self.page = self.page + 1
   }
}
1
SwiftyIso

Ich brauchte etwas Ähnliches für ein Projekt und meine Lösung war:

1 - Erstellen Sie eine Variable numberOfjectsInSubArray (Anfangswert 30 oder was auch immer Sie möchten)

2 - Erstellen Sie ein Unterfeld, um jedes Mal, wenn Sie auf "Mehr anzeigen" tippen, eine Reihe von Objekten aus Ihrem privateList-Array hinzuzufügen.

    let subArray = privateList?.subarrayWithRange(NSMakeRange(0, numberOfObjectsInSubArray))

Und benutze es weiter 

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

3- Wenn Sie mehr Objekte anzeigen müssen, führen Sie folgende Schritte aus:

func addMoreObjectsOnTableView () {

    numberOfObjectsInSubArray += 30

    if (numberOfObjectsInSubArray < privateList.count) {

        subArray = privateList?.subarrayWithRange(NSMakeRange(0, numberOfObjectsInSubArray))  

    } else {

        subArray = privateList?.subarrayWithRange(NSMakeRange(0, privateList.count))  
    }

    tableView.reloadData()
}

Ich hoffe, es hilft

1
scollaco

Eine andere Möglichkeit, dies zu tun, ist: Sie können einen Schwellenwert für das Abrufen von Elementen festlegen, während die Anforderung jedes Mal gesendet wird:

Nehmen wir an, Sie holen beim ersten Mal 20 Elemente ab. Sie speichern die zuletzt abgerufene Datensatz-ID oder Nummer, um eine Liste der nächsten 20 Elemente zu erhalten. 

let lastFetchedIndex = 20;

Ich gehe davon aus, dass Sie diese Einträge bereits in Ihrem myArray hinzugefügt haben. MyArray ist die Datenquelle von tableView. Jetzt enthält myArray 40 Objekte. Ich werde jetzt eine Liste von indexPaths von Zeilen erstellen, die jetzt in tableView eingefügt werden müssen.

var indexPathsArray = [NSIndexPath]()


for index in lastFetchedIndex..<myArray.count{
    let indexPath = NSIndexPath(forRow: index, inSection: 0)
    indexPathsArray.append(indexPath)

}

Hier aktualisiere ich meine tableView. Stellen Sie sicher, dass Ihre DataSource i mein myArray bereits aktualisiert hat. Damit kann es Zeilen richtig einfügen.

self.tableView.beginUpdates()
tableView!.insertRowsAtIndexPaths(indexPathsArray, withRowAnimation: .Fade)
self.tableView.endUpdates()
1
Shehzad Ali