web-dev-qa-db-fra.com

Table rapideVoir la pagination

J'ai réussi à travailler avec tableview avec l'analyse de codes. Mais il est possible que vous ayez 1000 éléments de plus, vous avez donc besoin de pagination lorsque vous faites défiler l'écran vers le bas. Je ne sais pas comment puis-je faire cela mes codes ci-dessous. Pour objective-c, j'ai beaucoup d'exemples, mais pour Swift, je n'ai pas trouvé d'exemple de travail. J'attends vos aides. Je pense que ce sera aider trop de gens. Je vous remercie ! 

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

Pour cela, vous devez également modifier le côté serveur.

  1. Le serveur acceptera fromIndex et batchSize dans l'URL API en tant que paramètre de requête. 

    let listUrlString =  "http://bla.com/json2.php?listType=" + listType + "&t=" + NSUUID().UUIDString + "&batchSize=" + batchSize + "&fromIndex=" + fromIndex
    
  2. Dans la réponse du serveur, il y aura une clé supplémentaire totalItems. Ceci sera utilisé pour identifier tous les articles reçus ou non. Un tableau ou des éléments fromIndex à batchSize nombre d'éléments.

Dans l'application

  1. La première loadItem() sera appelée avec fromIndex = 0 et batchSize = 20 (par exemple, dans viewDidLoad() ou viewWillAppear). removeAll éléments du tableau privateList avant d'appeler loadItem() pour la première fois

  2. Le serveur renvoie un tableau des 20 premiers éléments et le nombre total totalItems d'éléments sur le serveur.

  3. Ajoutez les 20 éléments du tableau privateList et rechargez tableView

  4. Dans la méthode tableView:cellForRowAtIndexPath, vérifiez si la cellule est la dernière. Et vérifiez si totalItems (serveur de formulaire) est supérieur à privateList.count. Cela signifie qu'il y a plus d'éléments sur le serveur à charger

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

Question:where is refresh ? will be scrolling ?

Actualisez après avoir ajouté de nouveaux éléments dans le tableau lorsque la réponse du serveur est reçue. (étape 3)

Le défilement déclenchera tableView:cellForRowAtIndexPath pour chaque cellule lorsque l'utilisateur fera défiler. Le code vérifie s'il s'agit de la dernière cellule et récupère les éléments restants. (étape 4) 

Exemple de projet ajouté: 
https://github.com/rishi420/TableViewPaging

50
Warif Akhand Rishi

Le moyen le plus efficace de le faire consiste à utiliser scrollviewDelegate dans tableview Ajoutez simplement UIScrollViewDelegate dans votre viewControllerIn view controller 

//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
}

Ignorer deux méthodes de ce délégué

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 ...

Si vous envoyez le numéro de page dans la demande d'API, c'est le moyen idéal pour implémenter la pagination dans votre application.

1) déclarer la variable page en cours avec la valeur initiale 0 et une valeur booléenne pour vérifier si une liste est chargée avec la valeur initiale false 

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

2) C'est la fonction qui obtient l'exemple de liste:

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

3) C'est la fonction qui incrémente le numéro de page et appelle la fonction API 

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

4) c’est la méthode qui sera appelée lorsque le scrollView défilera

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

P.S. le rôle bool isLoadingList consiste à empêcher la vue défilement d'obtenir plus de listes en un seul glissement vers le bas de la vue tableau.

9
MhmdRizk

C’est maintenant un peu plus facile avec l’ajout d’un nouveau protocole dans iOS10: UITableViewDataSourcePrefetching

https://developer.Apple.com/documentation/uikit/uitableview/pool/refuging

7
Paul Robinson

Ajoutez une autre section à votre table, laissez à cette section une seule ligne qui sera une cellule contenant un indicateur d'activité, pour indiquer le chargement.

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

voici un exemple de code pour la vue de collection:

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

J'avais besoin de quelque chose de similaire sur un projet et ma solution était:

1 - créer une variable numberOfObjectsInSubArray (valeur initiale 30 ou celle que vous souhaitiez)

2 - créez un sous-tableau pour ajouter plusieurs objets de votre tableau privateList chaque fois que je clique sur "afficher plus"

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

Et l'utiliser sur 

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

3- Chaque fois que vous avez besoin de montrer plus d'objets, faites:

func addMoreObjectsOnTableView () {

    numberOfObjectsInSubArray += 30

    if (numberOfObjectsInSubArray < privateList.count) {

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

    } else {

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

    tableView.reloadData()
}

J'espère que ça aide

1
scollaco

Une autre façon de procéder est la suivante: vous pouvez définir un seuil pour obtenir des éléments tout en envoyant une demande à chaque fois:

Disons que vous allez chercher 20 éléments pour la première fois. Vous sauvegarderez l'id ou le dernier numéro d'enregistrement récupéré pour obtenir la liste des 20 prochains éléments. 

let lastFetchedIndex = 20;

Je suppose que vous avez déjà ajouté ces enregistrements dans votre myArray. MyArray est la source de données de tableView. Maintenant, myArray contient 40 objets. Je vais faire une liste de chemins indexPaths qui doivent être insérés dans tableView maintenant.

var indexPathsArray = [NSIndexPath]()


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

}

Ici, je mets à jour mon tableView. Assurez-vous que votre source de données signifie que votre myArray a déjà été mis à jour. Pour qu'il puisse insérer des lignes correctement.

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