Android RecyclerView: Τι είναι, Μάθετε με απλά παραδείγματα
Τι είναι το RecyclerView Android?
The RecyclerView είναι ένα widget που είναι πιο ευέλικτη και προηγμένη έκδοση των GridView και ListView. Είναι ένα κοντέινερ για την εμφάνιση μεγάλων συνόλων δεδομένων, τα οποία μπορούν να μετακινηθούν αποτελεσματικά διατηρώντας περιορισμένο αριθμό προβολών. Μπορείτε να χρησιμοποιήσετε το γραφικό στοιχείο RecyclerView όταν έχετε συλλογές δεδομένων των οποίων τα στοιχεία αλλάζουν κατά το χρόνο εκτέλεσης εξαρτώνται από το συμβάν δικτύου ή τη δράση του χρήστη.
Προβολές
The Android Η πλατφόρμα χρησιμοποιεί τις κλάσεις View και ViewGroup για να σχεδιάσει στοιχεία στην οθόνη. Αυτές οι κλάσεις είναι αφηρημένες και επεκτείνονται σε διαφορετικές υλοποιήσεις για να ταιριάζουν σε μια περίπτωση χρήσης. Το TextView, για παράδειγμα, έχει έναν απλό σκοπό να εμφανίζει περιεχόμενο κειμένου στην οθόνη. Το EditText επεκτείνεται από την ίδια κλάση View και προσθέτει περισσότερες λειτουργίες για να μπορεί ο χρήστης να εισάγει δεδομένα.
Είναι δυνατό να δημιουργήσουμε τις δικές μας προσαρμοσμένες προβολές για να μπορέσουμε να επιτύχουμε μεγαλύτερη ευελιξία κατά την ανάπτυξη διεπαφών χρήστη. Η κλάση View παρέχει μεθόδους που μπορούμε να παρακάμψουμε για να σχεδιάσουμε στην οθόνη και ένα μέσο για να μεταβιβάσουμε παραμέτρους όπως το πλάτος, το ύψος και τα δικά μας προσαρμοσμένα χαρακτηριστικά που θα θέλαμε να προσθέσουμε στην προβολή μας για να συμπεριφέρεται όπως θα θέλαμε.
ViewGroups
Η κλάση ViewGroup είναι ένα είδος View, αλλά, σε αντίθεση με την απλή κλάση View, της οποίας η ευθύνη εμφανίζεται απλώς, η ViewGroup μας δίνει τη δυνατότητα να βάλουμε πολλές προβολές σε μία προβολή, στην οποία μπορούμε να αναφερθούμε ως σύνολο. Σε αυτήν την περίπτωση, η προβολή που δημιουργείται στο ανώτερο επίπεδο όπου προσθέτουμε άλλες απλές προβολές (μπορούμε επίσης να προσθέσουμε ομάδες προβολής) ονομάζεται "γονέας" και οι προβολές που προστίθενται μέσα είναι "παιδιά".
Μπορούμε να απεικονίσουμε μια προβολή ως πίνακα και μια ViewGroup ως πίνακα πινάκων. Δεδομένου ότι ένας πίνακας πινάκων είναι ένας πίνακας ο ίδιος, μπορούμε να δούμε πώς ένα ViewGroup μπορεί να αντιμετωπιστεί ως Προβολή.
var arr1 = [1,2,3] //imagine a simple View as an Array //we can imagine this as a NumberTextView which doesn't really exist //but we could imagine there's one that makes it easy to use numbers var arr2 = ["a","b","c"] // We can imagine this as another simple view var nestedArr = [arr1,arr2] //in our anology, we can now group views //together and the structure that would hold that would be what we call the ViewGroup
Το ViewGroup μας δίνει επίσης τη δυνατότητα να ορίσουμε πώς τα παιδιά είναι οργανωμένα μέσα στην προβολή, για παράδειγμα, τοποθετούνται κάθετα ή οριζόντια. Μπορούμε να έχουμε διαφορετικούς κανόνες αλληλεπίδρασης μέσα στο View. Για παράδειγμα, τα TextView που ακολουθούν το ένα το άλλο θα πρέπει να έχουν απόσταση 12dp ενώ τα ImageView που ακολουθούνται από το TextView θα πρέπει να έχουν απόσταση 5dp.
Αυτό θα συνέβαινε εάν αναπτύσσαμε το δικό μας ViewGroup από την αρχή. Για να διευκολύνετε αυτές τις διαμορφώσεις, Android παρέχει μια κλάση που ονομάζεται LayoutParams, την οποία μπορούμε να χρησιμοποιήσουμε για να εισάγουμε αυτές τις διαμορφώσεις.
Android τεκμηρίωση παρέχει ορισμένες προεπιλεγμένες παραμέτρους που θα εφαρμόζαμε κατά τη διαμόρφωση του δικού μας ViewGroup. Μερικές κοινές παράμετροι είναι αυτές που αφορούν το πλάτος, το ύψος και το περιθώριο. Από προεπιλογή, αυτές οι διαμορφώσεις έχουν τη δομή android:layout_height για το ύψος, για παράδειγμα, android:layout_width Από αυτή την άποψη, όταν δημιουργείτε το ViewGroup σας, μπορείτε περαιτέρω να δημιουργήσετε LayoutParams ειδικά για τον τρόπο που θα θέλατε να συμπεριφέρεται το ViewGroup σας.
Android συνοδεύεται από προεπιλεγμένες προβολές και ομάδες προβολής που μπορούμε να χρησιμοποιήσουμε για να κάνουμε πολλές από τις κοινές εργασίες που χρειαζόμαστε. Ένα παράδειγμα που αναφέραμε είναι ένα TextView. Αυτή είναι μια απλή προβολή που συνοδεύεται από παραμετροποιήσιμες πτυχές, όπως ύψος, πλάτος, μέγεθος κειμένου και παρόμοια. Έχουμε ένα ImageView για εμφάνιση εικόνων και EditText όπως είχαμε αναφέρει, μεταξύ πολλών άλλων. Android έχει επίσης προσαρμοσμένες ομάδες προβολής στις οποίες μπορούμε να προσθέσουμε τις προβολές μας και να έχουμε την αναμενόμενη συμπεριφορά.
Γραμμική διάταξη
Το LinearLayout μας επιτρέπει να προσθέσουμε στοιχεία Προβολής σε αυτό. Το LinearLayout είναι ένα χαρακτηριστικό προσανατολισμού που υπαγορεύει τον τρόπο με τον οποίο θα τοποθετηθεί στην οθόνη. Διαθέτει επίσης LinearLayout.LayoutParams που υπαγορεύουν τους κανόνες για τις προβολές μέσα, για παράδειγμα, το χαρακτηριστικό android:center_horizontal θα κεντράρει τις προβολές κατά μήκος του οριζόντιου άξονα, ενώ το `android:center_vertical θα κεντράρει το περιεχόμενο της προβολής στον κατακόρυφο άξονα.
Ακολουθούν μερικές εικόνες για να κατανοήσετε το κεντράρισμα. Θα θεωρούσαμε ότι αυτό είναι ένα απλό TextView μέσα σε χώρο 200px επί 200px, τα χαρακτηριστικά κεντραρίσματος θα το έκαναν να συμπεριφέρεται ως εξής.
android:center_horizontal

android:center_vertical

android:center

Βασικά στοιχεία του RecyclerView

Ακολουθούν τα σημαντικά στοιχεία του RecyclerView:
RecyclerView.Adapter
Βάση #1 – Μοτίβο προσαρμογέα
Ένας προσαρμογέας είναι μια συσκευή που μετατρέπει χαρακτηριστικά συστήματος ή συσκευής σε αυτά μιας κατά τα άλλα μη συμβατής συσκευής ή συστήματος. Ορισμένα από αυτά τροποποιούν τα χαρακτηριστικά σήματος ή ισχύος, ενώ άλλα προσαρμόζουν απλώς τη φυσική μορφή ενός βύσματος σε έναν άλλο.
Ένα απλό παράδειγμα που βρίσκουμε στην πραγματική ζωή για να εξηγήσουμε έναν προσαρμογέα είναι όταν πρέπει να συνδέσουμε συσκευές μεταξύ τους, αλλά έχουν θύρες σύνδεσης που δεν ταιριάζουν μεταξύ τους. Αυτό μπορεί να συμβαίνει όταν επισκέπτεστε μια διαφορετική χώρα όπου χρησιμοποιούν διαφορετικά είδη πριζών. Εάν έχετε μαζί σας φορτιστή τηλεφώνου ή φορητού υπολογιστή, θα ήταν αδύνατο να τον συνδέσετε στις πρίζες. Ωστόσο, δεν θα τα παρατήσετε, αλλά απλώς θα λάβετε έναν προσαρμογέα που θα έμπαινε ανάμεσα στην πρίζα και τον φορτιστή σας και θα επέτρεπε τη φόρτιση.
Αυτό συμβαίνει στον προγραμματισμό όταν θέλουμε να συνδέσουμε δύο δομές δεδομένων μαζί για να εκπληρώσουμε την εργασία, αλλά οι προεπιλεγμένες θύρες τους δεν έχουν τρόπο να επικοινωνήσουν μεταξύ τους.
Θα χρησιμοποιήσουμε το απλό παράδειγμα μιας συσκευής και ενός φορτιστή. Θα έχουμε δύο περιπτώσεις φορτιστών. Ένα αμερικανικό και ένα βρετανικό
class AmericanCharger() { var chargingPower = 10 } class BritishCharger(){ var charginPower = 5 }
Στη συνέχεια, θα δημιουργήσουμε δύο συσκευές
class AmericanDevice() class BritishDevice()
Για παράδειγμα, μπορούμε στη συνέχεια να δημιουργήσουμε ορισμένες περιπτώσεις των συσκευών για αναπαραγωγή.
var myAmericanPhone = new AmericanDevice() var myBritishPhone = new BritishDevice()
Στη συνέχεια θα εισαγάγουμε την έννοια της φόρτισης και για τις δύο συσκευές προσθέτοντας μια μέθοδο στις συσκευές που ονομάζεται charge() .
Η μέθοδος παίρνει ως είσοδο τον αντίστοιχο φορτιστή και κάνει τη φόρτιση βάσει αυτού.
sealed trait Device class AmericanDevice : Device{ fun charge(charger:AmericanCharger){ //Do some American charging } } class BritishDevice: Device{ fun charge(charger:BritishCharger){ //Do some British charging } }
Σε αυτήν την περίπτωση, με βάση την αναλογία μας, θα χρειαζόμασταν για τον ένα ή τον άλλο λόγο να χρησιμοποιήσουμε έναν BritishCharger όταν χρησιμοποιούμε μια AmericanDevice ή το αντίστροφο.
Στον κόσμο του προγραμματισμού, αυτό συμβαίνει συνήθως όταν αναμιγνύουμε βιβλιοθήκες μεταξύ τους που προσφέρουν την ίδια λειτουργικότητα (στο περιβάλλον μας, η κοινή μας λειτουργικότητα φορτίζει). Θα πρέπει να βρούμε έναν τρόπο να το επιτρέψουμε.
Αν ακολουθήσουμε την αναλογία, θα χρειαστεί να πάμε σε ένα κατάστημα ηλεκτρονικών ειδών και να αγοράσουμε έναν προσαρμογέα που θα μας επιτρέψει να φορτίσουμε τις AmericanDevices που δίνονται στους BritishChargers. Από την άποψη του προγραμματισμού, θα είμαστε εμείς που θα είμαστε ο κατασκευαστής του προσαρμογέα.
Θα φτιάξουμε έναν προσαρμογέα για το ένα που ταιριάζει ακριβώς με το μοτίβο που θα χρειαζόμασταν για τη δημιουργία του άλλου. Θα το εφαρμόσουμε ως κλάση ως εξής. Δεν χρειάζεται απαραίτητα να είναι κατηγορία και θα μπορούσε να είναι μια συνάρτηση που υπογραμμίζει αυτό που κάνει γενικά το μοτίβο του προσαρμογέα. Θα χρησιμοποιήσουμε μια τάξη όπως ταιριάζει με την περισσότερη χρήση Android.
class AmericanToBritishChargerAdapter(theAmericanCharger:AmericanCharger){ fun returnNewCharger(): BritishCharger{ //convert the American charger to a BritishCharger //we would change the American charging functionality //to British charging functionality to make sure the //adapter doesn't destroy the device. The adapter could //, for example, control the power output by dividing by 2 //our adapter could encompass this functionality in here var charingPower:Int = charger.chargingPower / 2 var newBritishCharger = new BritishCharger() newBritishCharger.chargingPower = theAmericanCharger.chargingPower/2 return newBritishCharger } }
Στον κόσμο του προγραμματισμού, η διαφορά στις πρίζες είναι ανάλογη με τη διαφορά στις μεθόδους φόρτισης στο εσωτερικό. Οι φορτιστές που έχουν διαφορετικές μεθόδους θα καθιστούσαν αδύνατη τη χρήση των φορτιστών.
var myBritishDevice = new BritishDevice() var americanChargerIFound = new AmericanCharger()
Η προσπάθεια να καλέσετε τη μέθοδο charge() στο myBritishDevice με το americanChargerIFound δεν θα λειτουργούσε καθώς η AmericanDevice δέχεται μόνο έναν AmericanCharger
Άρα είναι αδύνατο να γίνει αυτό
var myBritishDevice = new BritishDevice() var americanChargerIFound = new AmericanCharger() myBritishDevice.charge(americanChargerIFound)
Σε αυτό το σενάριο ο προσαρμογέας που δημιουργήσαμε
Το AmericanToBritishChargerAdapter μπορεί τώρα να είναι χρήσιμο. Μπορούμε να χρησιμοποιήσουμε τη μέθοδο returnNewCharger() για να δημιουργήσουμε έναν νέο BritishCharger, τον οποίο μπορούμε να χρησιμοποιήσουμε για να φορτίσουμε. Το μόνο που χρειαζόμαστε είναι να δημιουργήσουμε μια παρουσία του προσαρμογέα μας και να τον τροφοδοτήσουμε με τον AmericanCharger που έχουμε και θα δημιουργήσει έναν BritishCharger που μπορούμε να χρησιμοποιήσουμε
var myBritishDevice = new BritishDevice() var americanChargerIFound = new AmericanCharger() //We create the adapter and feed it the americanCharger var myAdapter = AmericanToBritishChargerAdapter(theAmericanCharger) //calling returnNewCharger from myAdapter would return a BritishCharger var britishChargerFromAdapter = myAdapter.returnNewCharger() //and once we have the britishCharger we can now use it myBritishDevice.charge(britishChargerFromAdapter)
RecyclerView.LayoutManager
Όταν έχουμε να κάνουμε με ένα ViewGroup, θα έχουμε τις Προβολές τοποθετημένες μέσα σε αυτό. Το LayoutManager θα έχει το καθήκον να περιγράφει τον τρόπο με τον οποίο τοποθετούνται οι Προβολές στο εσωτερικό.
Για λόγους σύγκρισης, όταν εργαζόμαστε με το Linearlayout ViewGroup, η περίπτωση χρήσης που θέλουμε είναι η δυνατότητα τοποθέτησης των στοιχείων είτε κάθετα είτε οριζόντια. Αυτό υλοποιείται εύκολα με την προσθήκη ενός χαρακτηριστικού προσανατολισμού, το οποίο μας λέει πώς θα τοποθετηθεί η γραμμική διάταξη στην οθόνη. Μπορούμε να το κάνουμε αυτό χρησιμοποιώντας android:orientation=VERTICAL|HORIZONTAL
αποδίδουν.
Έχουμε επίσης ένα άλλο ViewGroup που ονομάζεται GridLayout, είναι περίπτωση χρήσης όταν θέλουμε να τοποθετήσουμε τις προβολές σε μια ορθογώνια δομή Grid. Αυτό μπορεί να οφείλεται σε λόγους όπως η εύκολη κατανάλωση των δεδομένων που παρουσιάζουμε στον χρήστη της εφαρμογής. Σχεδιασμένα, το GridLayout επιτρέπει διαμορφώσεις που θα σας βοηθήσουν στην επίτευξη αυτού του στόχου, έχοντας διαμορφώσεις όπου μπορούμε να ορίσουμε τις διαστάσεις του πλέγματος, για παράδειγμα, μπορούμε να έχουμε ένα πλέγμα 4×4, πλέγμα 3 x 2.
RecyclerView.ViewHolder
Το ViewHolder είναι μια αφηρημένη κλάση που επεκτείνουμε επίσης από το RecyclerView. Το ViewHolder μάς παρέχει κοινές μεθόδους για να μας βοηθήσει να αναφερθούμε σε μια προβολή που έχουμε τοποθετήσει στο RecyclerView, ακόμη και αφού το μηχάνημα ανακύκλωσης στο RecyclerView άλλαξε διάφορες αναφορές που δεν γνωρίζουμε.
Μεγάλοι Λίστες
Τα RecyclerViews χρησιμοποιούνται όταν θέλουμε να παρουσιάσουμε ένα πραγματικά μεγάλο σύνολο προβολών στον χρήστη, χωρίς ωστόσο να εξαντλούμε RAM στη συσκευή μας για κάθε εμφάνιση της προβολής που δημιουργήθηκε.
Εάν λαμβάναμε την περίπτωση μιας λίστας επαφών, θα είχαμε μια γενική ιδέα για το πώς θα ήταν μια επαφή στη λίστα. Αυτό που θα κάναμε στη συνέχεια είναι να δημιουργήσουμε μια διάταξη προτύπου – η οποία είναι στην πραγματικότητα μια προβολή – με υποδοχές όπου θα γεμίζουν διάφορα δεδομένα από τη λίστα επαφών μας. Ακολουθεί ένας ψευδοκώδικας που εξηγεί ολόκληρο τον σκοπό:
//OneContactView <OneContact> <TextView>{{PlaceHolderForName}}</TextView> <TextView>{{PlaceHolderForAddress}}</TextView> <ImageView>{{PlaceHolderForProfilePicture}}</ImageView> <TextView>{{PlaceHolderForPhoneNumber}}</TextView> </OneContact>
Τότε θα είχαμε μια Λίστα Επαφών αυτού του είδους
<ContactList> </ContactList>
Αν συμβαίνει αυτό, κάναμε σκληρή κωδικοποίηση των περιεχομένων, δεν θα είχαμε έναν προγραμματικό τρόπο προσθήκης νέου περιεχομένου στη λίστα χωρίς να ξαναγράψουμε την εφαρμογή. Ευτυχώς για εμάς. Η προσθήκη μιας προβολής σε μια ομάδα προβολής υποστηρίζεται από ένα addView(view:View)
μέθοδος.
Ακόμα κι αν συμβαίνει αυτό, δεν είναι ο τρόπος με τον οποίο το RecyclerView προσθέτει προβολές παιδιών σε αυτό.
Στην περίπτωση χρήσης μας, θα είχαμε μια μακρά λίστα επαφών. Για κάθε επαφή στη λίστα, θα χρειαστεί να δημιουργήσουμε το OneContactView και να συμπληρώσουμε τα δεδομένα μέσα στην Προβολή, ώστε να ταιριάζουν με τα πεδία της κλάσης Επαφών. Στη συνέχεια, μόλις έχουμε την προβολή, θα πρέπει να την προσθέσουμε στο RecyclerView για να εμφανιστεί η λίστα.
data class Contact(var name:String, var address:String, var pic:String, var phoneNumber:Int) var contact1 = Contact("Guru","Guru97", "SomePic1.jpg", 991) var contact2 = Contact("Guru","Guru98", "SomePic2.jpg", 992) var contact3 = Contact("Guru","Guru99", "SomePic3.jpg", 993) var myContacts:ArrayList<Contact> = arrayListOf<Contact>(contact1,contact2,contact3)
Έχουμε μια σειρά επαφών που ονομάζεται OneContactView. Περιέχει υποδοχές για λήψη περιεχομένων από την κλάση Επαφή και εμφάνιση τους. Στο RecyclerView πρέπει να προσθέσουμε Προβολές σε αυτό για να μας βοηθήσει με την ικανότητα ανακύκλωσής του.
Το RecyclerView δεν μας επιτρέπει πραγματικά να προσθέσουμε προβολή, αλλά μας δίνει τη δυνατότητα να προσθέσουμε ένα ViewHolder. Έτσι, σε αυτό το σενάριο, έχουμε δύο κομμάτια πραγμάτων που θέλουμε να συνδέσουμε αλλά δεν ταιριάζουν. Εδώ μπαίνει ο προσαρμογέας μας. Το RecyclerView μας παρέχει έναν προσαρμογέα που μοιάζει πολύ με τον δικό μας AmericanToBritishChargerAdapter()
από νωρίτερα, αυτό μας επέτρεψε να μετατρέψουμε τον AmericanCharger μας, ο οποίος δεν μπορούσε να χρησιμοποιηθεί με τη BritishDevice μας, σε κάτι χρησιμοποιήσιμο, παρόμοιο με το τροφοδοτικό στην πραγματική ζωή.
Σε αυτό το σενάριο, ο προσαρμογέας θα έπαιρνε τη σειρά των Επαφών και την Προβολή μας και από εκεί θα δημιουργούσε ViewHolders που το RecyclerView είναι πρόθυμο να δεχτεί.
Το RecyclerView παρέχει μια διεπαφή που μπορούμε να επεκτείνουμε για να δημιουργήσουμε τον προσαρμογέα μας μέσω της κλάσης RecyclerView.Adapter. Μέσα σε αυτόν τον προσαρμογέα υπάρχει ένας τρόπος δημιουργίας της κλάσης ViewHolder με την οποία θέλει να εργαστεί το RecyclerView. Έτσι, αυτό που έχουμε είναι η ίδια κατάσταση με πριν, αλλά με ένα επιπλέον πράγμα, αυτό είναι ο προσαρμογέας.
Έχουμε μια σειρά από Επαφές, μια προβολή για εμφάνιση μιας επαφής OneContactView. Το RecyclerView είναι μια λίστα προβολών που παρέχουν υπηρεσίες ανακύκλωσης αλλά είναι πρόθυμοι να δεχτούν μόνο ViewHolders
Αλλά σε αυτό το σενάριο, έχουμε τώρα την κλάση RecyclerView.Adapter, η οποία έχει μια μέθοδο για τη δημιουργία ViewHolders μέσα.
fun createViewHolder(@NonNull parent: ViewGroup, viewType: Int): ViewHolder
Το RecyclerView.ViewHolder είναι μια αφηρημένη κλάση που παίρνει την προβολή μας ως όρισμα και τη μετατρέπει σε ViewHolder.
Χρησιμοποιεί το μοτίβο περιτυλίγματος που χρησιμοποιείται για την επέκταση των ικανοτήτων των κλάσεων.
Groundwork #2 – Μοτίβο περιτυλίγματος
Θα χρησιμοποιήσουμε ένα απλό παράδειγμα για να δείξουμε πώς μπορούμε να κάνουμε τα ζώα να μιλήσουν.
sealed trait Animal{ fun sound():String } data class Cat(name:String):Animal{ fun sound(){ "Meow" } } data class Dog(name:String):Animal{ fun sound(){ "Woof" } } var cat1 = Cat("Tubby") var dog1 = Dog("Scooby") cat1.sound() //meow dog1.sound() //woof
Στο παραπάνω παράδειγμα, έχουμε δύο ζώα. Αν κατά τύχη, θέλαμε να προσθέσουμε μια μέθοδο για να κάνουμε την ομιλία, αλλά ο συγγραφέας της βιβλιοθήκης δεν ήταν διασκεδαστικός, θα μπορούσαμε να βρούμε έναν τρόπο. Αυτό που χρειαζόμαστε είναι ένα περιτύλιγμα για την τάξη των Ζώων. Θα το κάναμε αυτό παίρνοντας το Animal ως κατασκευαστή για την τάξη μας
class SpeechPoweredAnimalByWrapper(var myAnimal:Animal){ fun sound(){ myAnimal.sound() } speak(){ println("Hello, my name is ${myAnimal.name}") } }
Τώρα μπορούμε να περάσουμε σε μια παρουσία ζώων στο SpeechPoweredAnimalByWrapper. Η κλήση της μεθόδου sound() σε αυτήν θα καλούσε τη μέθοδο pass in animal sound(). Έχουμε επίσης μια πρόσθετη μέθοδο speak(), η οποία μετράει ως νέα λειτουργικότητα που προσθέτουμε στα ζώα. Μπορούμε να τη χρησιμοποιήσουμε ως εξής:
var cat1 = Cat("Garfield") cat1.sound()//"meow" cat1.speak()// doesn't work as it isn't implemented var talkingCat = new SpeechPoweredAnimalByWrapper(cat1) talkingCat.sound() //"meow" the sound method calls the one defined for cat1 talkingCat.speak() //"Hello, my name is Garfield"
Χρησιμοποιώντας αυτό το μοτίβο, μπορούμε να παρακολουθήσουμε μαθήματα και να προσθέσουμε λειτουργικότητα. Το μόνο που χρειαζόμαστε είναι να περάσουμε είναι μια παρουσία κλάσης και νέες μέθοδοι που ορίζονται από την κλάση αναδίπλωσης.
Στην παραπάνω περίπτωσή μας, χρησιμοποιήσαμε μια συγκεκριμένη κατηγορία. Είναι επίσης δυνατό να εφαρμοστεί το ίδιο σε μια τάξη Abstract. Θα πρέπει να προσθέσουμε την αλλαγή της κλάσης SpeechPoweredAnimalByWrapper σε abstract και τελειώσαμε. Θα αλλάξουμε το όνομα της τάξης σε κάτι πιο σύντομο για να το κάνουμε πιο ευανάγνωστο.
abstract class SpeechPowered(var myAnimal:Animal){ fun sound(){ myAnimal.sound() } speak(){ println("Hello, my name is ${myAnimal.name}") } }
Είναι το ίδιο με πριν, αλλά θα σήμαινε κάτι άλλο. Σε μια κανονική τάξη, μπορούμε να έχουμε ένα παράδειγμα μιας κλάσης με τον ίδιο τρόπο που δημιουργήσαμε τα cat1 και dog1. Οι αφηρημένες τάξεις, ωστόσο, δεν προορίζονται να δημιουργηθούν, αλλά προορίζονται να επεκτείνουν άλλες τάξεις. Πώς θα χρησιμοποιούσαμε λοιπόν τη νέα αφηρημένη κλάση SpeechPowered(var myAnimal:Animal). Μπορούμε να το χρησιμοποιήσουμε δημιουργώντας νέες κλάσεις που θα το επεκτείνουν και στη συνέχεια θα αποκτήσουν τη λειτουργικότητά του.
Στο παράδειγμά μας, θα δημιουργήσουμε μια κλάση SpeechPoweredAnimal που επεκτείνει την κλάση
class SpeechPoweredAnimal(var myAnimal:Animal):SpeechPowered(myAnimal)
var cat1 = Cat("Tubby") var speakingKitty = SpeechPoweredAnimal(cat1) speakingKitty.speak() //"Hello, my name is Tubby"
Αυτό είναι το ίδιο μοτίβο που χρησιμοποιείται στο ViewHolder. Η κλάση RecyclerView.ViewHolder είναι μια αφηρημένη κλάση που προσθέτει λειτουργικότητα στην προβολή, όπως ακριβώς έχουμε προσθέσει τη μέθοδο ομιλίας στα ζώα. Η προστιθέμενη λειτουργικότητα είναι αυτή που το κάνει να λειτουργεί όταν ασχολείστε με το RecyclerView.
Έτσι θα δημιουργούσαμε ένα OneContactViewHolder από το OneContactView
//The View argument we pass is converted to a ViewHolder which uses the View to give it more abilities and in turn work with the RecyclerView class OneContactViewHolder(ourContactView: View) : RecyclerView.ViewHolder(ourContactView)
Το RecyclerView έχει έναν προσαρμογέα που μας επιτρέπει να συνδέσουμε τον πίνακα επαφών μας στο ContactsView με το RecyclerView
Προσθήκη προβολής
Το ViewGroup δεν επανασχεδιάζει αυτόματα το ViewGroup αλλά ακολουθεί ένα συγκεκριμένο χρονοδιάγραμμα. Μπορεί στη συσκευή σας να επανασχεδιάζει κάθε 10 ms ή 100 ms, ή αν επιλέξουμε έναν παράλογο αριθμό, ας πούμε 1 λεπτό όταν προσθέτουμε μια προβολή σε μια ομάδα προβολής, θα δείτε τις αλλαγές 1 λεπτό αργότερα, όταν το ViewGroup "ανανεωθεί".
RecyclerView.Recycler
Βάση #3. Προσωρινή αποθήκευση
Ένα από τα καλύτερα παραδείγματα όπου κάνουμε τακτικά ανανεώσεις είναι το πρόγραμμα περιήγησης. Ας φανταστούμε, για παράδειγμα, ο ιστότοπος που επισκεπτόμαστε είναι στατικός και δεν στέλνει περιεχόμενο δυναμικά, θα πρέπει να συνεχίσουμε να ανανεώνουμε για να δούμε τις αλλαγές.
Για αυτό το παράδειγμα, ας φανταστούμε ότι ο εν λόγω ιστότοπος είναι το twitter. Θα είχαμε μια σειρά από στατικά tweets στη λίστα και ο μόνος τρόπος που θα μπορούσαμε να δούμε νέα Tweets θα ήταν κάνοντας κλικ στο κουμπί ανανέωσης για να ανακτήσουμε ξανά το περιεχόμενο.
Το να βάψετε ξανά ολόκληρη την οθόνη είναι προφανώς ένα δαπανηρό πράγμα. Αν φανταζόμασταν αν ίσχυε, είχαμε περιορισμένο εύρος ζώνης με τον πάροχο τηλεφώνου μας. Και η λίστα των tweet μας είχε πολλές εικόνες και βίντεο, θα ήταν δαπανηρό να κατεβάσουμε ξανά όλο το περιεχόμενο της σελίδας σε κάθε ανανέωση.
Θα χρειαζόμασταν έναν τρόπο για να αποθηκεύσουμε τα ήδη φορτωμένα Tweet και να διασφαλίσουμε ότι το επόμενο αίτημά μας έχει τη δυνατότητα να πει τα Tweets που έχει ήδη. Επομένως, δεν κατεβάζει ξανά τα πάντα και λαμβάνει μόνο τα νέα Tweet που έχει και επίσης ελέγχει αν κάποιο Tweet που είχε αποθηκευτεί τοπικά δεν είναι πλέον εκεί, ώστε να μπορεί να το διαγράψει τοπικά. Αυτό που περιγράφουμε ονομάζεται προσωρινή αποθήκευση.
Οι πληροφορίες που στέλνουμε στον ιστότοπο σχετικά με το περιεχόμενο που έχουμε ονομάζονται μεταδεδομένα. Επομένως, στην πραγματική έννοια δεν λέμε απλώς "θέλουμε να φορτώσουμε τον ιστότοπό σας", λέμε "θέλουμε να φορτώσουμε τον ιστότοπό σας και εδώ είναι μερικά από τα περιεχόμενα που είχαμε ήδη αποθηκεύσει από την τελευταία φορά που φορτώσαμε, χρησιμοποιήστε το για να Στείλτε μας μόνο ό,τι δεν υπάρχει, ώστε να μην χρησιμοποιούμε πολύ εύρος ζώνης καθώς δεν έχουμε πολλούς πόρους."
Κλήσεις διάταξης – Η λίστα Tweet πρέπει να είναι τρελή
Ένα παράδειγμα κλήσεων διάταξης είναι το scrollToPosition
Αυτό είναι ένα συνηθισμένο παράδειγμα που υπάρχει σε πράγματα όπως οι εφαρμογές συνομιλίας. Εάν κάποιος σε ένα νήμα συνομιλίας απαντήσει σε ένα συννεφάκι συνομιλίας προηγουμένως, ορισμένες εφαρμογές συνομιλίας περιλαμβάνουν την απάντηση και έναν σύνδεσμο προς το συννεφάκι συνομιλίας, το οποίο κάνοντας κλικ σας οδηγεί στο σημείο όπου ήταν το αρχικό σας μήνυμα.
Στην περίπτωση αυτή, καλούμε αυτήν τη μέθοδο προτού προσθέσουμε ένα LayoutManager στο RecyclerView μας και προτού έχουμε έναν RecyclerView.Adapter, το scrollToPosition(n:Int) απλώς αγνοείται.
Επικοινωνία μεταξύ RecyclerView Components
Βάση #4. Επανακλήσεις
Το RecyclerView, κάνοντας τη δουλειά του, έχει πολλά κινούμενα μέρη. Πρέπει να ασχοληθεί με το LayoutManager που μας λέει πώς να οργανώσουμε τις Προβολές, είτε Γραμμικά είτε σε Πλέγμα. Πρέπει να αντιμετωπίσει έναν προσαρμογέα που κάνει τη δουλειά της μετατροπής της ContactList των αντικειμένων μας σε Views OneContactView και στη συνέχεια σε ViewHolders OneContactViewHolder που το RecyclerView είναι πρόθυμο να λειτουργήσει σύμφωνα με τις μεθόδους που μας παρέχει.
Η πρώτη ύλη για το RecyclerView είναι οι Προβολές μας, π.χ. OneContactView και η πηγή δεδομένων.
contactList:Array<Contact>
Χρησιμοποιήσαμε ένα απλό σενάριο ως σημείο εκκίνησης για να πάρουμε μια αίσθηση του τι προσπαθεί να επιτύχει το RecyclerView.
Μια βασική περίπτωση του πότε θα είχαμε μια στατική συστοιχία 1000 επαφών που θέλουμε να δείξουμε στον χρήστη είναι εύκολα κατανοητή.
Το μηχάνημα RecyclerView αρχίζει πραγματικά να παίρνει ζωή όταν η λίστα δεν είναι πλέον στατική.
Με μια δυναμική λίστα, πρέπει να σκεφτούμε τι συμβαίνει στην προβολή στην οθόνη όταν προσθέτουμε ένα στοιχείο στη λίστα ή αφαιρούμε ένα στοιχείο από τη λίστα.
RecyclerView.LayoutManager
Εκτός από το να αποφασίσουμε πώς θα διατυπωθούν οι απόψεις μας είτε Γραμμικά είτε σε Πλέγμα. Το LayoutManager κάνει πολλή δουλειά κάτω από την κουκούλα βοηθώντας τον Ανακυκλωτή να γνωρίζει πότε να κάνει την Ανακύκλωση.
Είναι υπεύθυνο για την παρακολούθηση των Προβολών που είναι ορατές επί του παρόντος στην οθόνη και για την επικοινωνία με αυτές τις πληροφορίες στον μηχανισμό ανακύκλωσης. Καθώς ένας χρήστης κάνει κύλιση προς τα κάτω, ο διαχειριστής διάταξης είναι υπεύθυνος να ενημερώνει το σύστημα ανακύκλωσης για τις προβολές που δεν εστιάζουν στο επάνω μέρος, ώστε να μπορούν να επαναχρησιμοποιηθούν αντί να παραμείνουν εκεί και να καταναλώσουν μνήμη ή αντί να τις καταστρέψουν και να χρειαστεί να δημιουργήσουν καινούρια.
Αυτό σημαίνει ότι το LayoutManager πρέπει να παρακολουθεί πού βρίσκεται ο χρήστης καθώς κάνει κύλιση στη λίστα μας. Αυτό το κάνει έχοντας μια λίστα με θέσεις που είναι βάση ευρετηρίου, δηλαδή το πρώτο στοιχείο είναι να ξεκινά από το 0 και να αυξάνεται για να ταιριάζει με τον αριθμό των στοιχείων στη λίστα μας.
Εάν μπορούμε να προβάλουμε 10 στοιχεία στη λίστα ας πούμε 100, στην αρχή, ο LayoutManager γνωρίζει ότι έχει εστιάσει την προβολή-0 μέχρι την Προβολή-9 Καθώς κάνουμε κύλιση, το LayoutManager μπορεί να υπολογίσει τις προβολές που βγαίνουν της εστίασης.
Το LayoutManager μπορεί να απελευθερώσει αυτές τις προβολές στον μηχανισμό Ανακύκλωσης, ώστε να μπορούν να επαναχρησιμοποιηθούν (μπορούν να συνδεθούν νέα δεδομένα σε αυτές, π.χ. τα δεδομένα επαφής μιας Προβολής μπορούν να αφαιρεθούν και τα νέα δεδομένα επαφής από το επόμενο τμήμα μπορούν να αντικαταστήσουν τα σύμβολα κράτησης θέσης).
Θα ήταν μια ευχάριστη περίπτωση εάν η λίστα που έχουμε είναι στατική, αλλά μια από τις πιο συνηθισμένες περιπτώσεις χρήσης ενός RecyclerView είναι με δυναμικές λίστες όπου τα δεδομένα μπορούν να προέρχονται από ένα διαδικτυακό τελικό σημείο ή ακόμα και από έναν αισθητήρα. Όχι μόνο προστίθενται δεδομένα, αλλά τα δεδομένα στη Λίστα μας μερικές φορές αφαιρούνται ή ενημερώνονται.
Η δυναμική κατάσταση των δεδομένων μας μπορεί να κάνει πολύ δύσκολο να συλλογιστούμε σχετικά με το LayoutManager. Για αυτόν τον λόγο, το LayoutManager διατηρεί μια δική του λίστα σχετικά με τα στοιχεία και τις θέσεις, η οποία είναι ξεχωριστή από τη Λίστα που χρησιμοποιεί το στοιχείο Ανακύκλωσης. Αυτό διασφαλίζει ότι κάνει σωστά τη διάταξη της.
Ταυτόχρονα, το LayoutManager του RecyclerView δεν θέλει να παραποιήσει τα δεδομένα που διαθέτει. Προκειμένου να λειτουργεί σωστά, το LayoutManager συγχρονίζεται με τον προσαρμογέα RecyclerView.Adapter σε δεδομένα διαστήματα (60ms) μοιράζοντας πληροφορίες σχετικά με τα στοιχεία της λίστας μας. δηλ. Στοιχεία που προστέθηκαν, ενημερώθηκαν, αφαιρέθηκαν, μετακινήθηκαν από τη μια θέση στην άλλη). Το LayoutManager, μόλις λάβει αυτές τις πληροφορίες, αναδιοργανώνει τα περιεχόμενα στην οθόνη για να ταιριάζουν με τις αλλαγές όταν είναι απαραίτητο.
Πολλές από τις βασικές λειτουργίες που ασχολούνται με το RecylerView περιστρέφονται γύρω από την επικοινωνία μεταξύ του RecyclerView.LayoutManager και του RecyclerView.Adapter που αποθηκεύει τις λίστες μας με μερικές φορές στατικά ή μερικές φορές δυναμικά δεδομένα.
Επιπλέον, το RecyclerView μάς παρουσιάζει μεθόδους που μπορούμε να χρησιμοποιήσουμε για να ακούσουμε συμβάντα όπως το onBindViewHolder όταν το RecyclerView.Adapter δεσμεύει περιεχόμενο από τη Λίστα μας, π.χ. μια επαφή σε ένα ViewHolder, έτσι ώστε τώρα να συνηθίσει να εμφανίζει τις πληροφορίες στην οθόνη.
Ένα άλλο είναι το onCreateViewHolder, το οποίο μας ενημερώνει πότε το RecyclerView. Ο προσαρμογέας παίρνει μια κανονική προβολή όπως το OneContactView και τη μετατρέπει σε ένα στοιχείο ViewHolder με το οποίο μπορεί να λειτουργήσει το RecyclerView. Από το ViewHolder μας για χρήση από το RecyclerView. onViewDetached
Εκτός από τους βασικούς μηχανισμούς που επιτρέπουν την Ανακύκλωση. Το RecyclerView παρέχει τρόπους προσαρμογής της συμπεριφοράς χωρίς να επηρεάζεται η Ανακύκλωση.
Η επαναχρησιμοποίηση των προβολών καθιστά δύσκολο να κάνουμε κοινά πράγματα που έχουμε συνηθίσει να κάνουμε με στατικές προβολές, όπως η αντίδραση σε συμβάντα onClick.
Όπως γνωρίζουμε ότι το RecyclerView.LayoutManager
που παρουσιάζει τις Προβολές στον χρήστη μπορεί για μια στιγμή να έχει διαφορετική λίστα στοιχείων από το RecyclerView.Adapter
που έχει τη λίστα που έχουμε αποθηκεύσει σε μια βάση δεδομένων ή μέσω ροής από μια πηγή. Η απευθείας τοποθέτηση συμβάντων OnClick στις Προβολές μπορεί να οδηγήσει σε απροσδόκητη συμπεριφορά, όπως η διαγραφή της λανθασμένης επαφής ή η αλλαγή.
Gradle
Αν θέλουμε να χρησιμοποιήσουμε το RecyclerView, πρέπει να το προσθέσουμε ως εξάρτηση στο αρχείο build .gradle.
Στο παρακάτω παράδειγμα χρησιμοποιήσαμε την υλοποίηση "androidx.recyclerview:recyclerview:1.1.0" που είναι η πιο πρόσφατη έκδοση σύμφωνα με αυτό το άρθρο.
Αφού προσθέσουμε την εξάρτηση στο δικό μας Gradle αρχείο, θα μας ζητηθεί Android Στούντιο προς Syncχρονομετρήστε τις αλλαγές,
Αυτό είναι το πώς μας Gradle Το αρχείο θα μοιάζει με την προσθήκη ενός RecyclerView σε ένα κενό έργο με μόνο τις προεπιλογές.
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 29 buildToolsVersion "29.0.2" defaultConfig { applicationId "com.guru99.learnrecycler" minSdkVersion 17 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation "androidx.recyclerview:recyclerview:1.1.0" }
Έχουμε μόνο ένα αρχείο διάταξης αυτή τη στιγμή. Θα ξεκινήσουμε με ένα απλό παράδειγμα όπου θα χρησιμοποιήσουμε ένα RecyclerView για να εμφανίσουμε μια λίστα με ονόματα φρούτων στην οθόνη.
Λίστα αντικειμένων
Θα πλοηγηθούμε στο αρχείο MainActivity και θα δημιουργήσουμε έναν πίνακα με ονόματα φρούτων ακριβώς πριν από τη μέθοδο onCreate() που δημιουργήθηκε κατά τη ρύθμιση.
package com.guru99.learnrecycler import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity() { var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
Ο επόμενος στόχος μας θα είναι να παρουσιάσουμε αυτήν τη λίστα στην οθόνη χρησιμοποιώντας ένα RecyclerView.
Για να το κάνουμε αυτό, θα πλοηγηθούμε στον κατάλογο διάταξης που περιέχει τις Διατάξεις μας και θα δημιουργήσουμε μια Προβολή που θα είναι υπεύθυνη για την εμφάνιση ενός φρούτου.
Διάταξη που θα χρησιμοποιηθεί για κάθε στοιχείο στη λίστα μας
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/fruitName" /> </TextView>
Στο TextView παραπάνω, προσθέσαμε ένα πεδίο αναγνωριστικού που θα χρησιμοποιηθεί για τον προσδιορισμό μιας Προβολής.
Δεν δημιουργείται από προεπιλογή. Έχουμε το TextView το αναγνωριστικό fruitName για να ταιριάζει με τα δεδομένα, τα οποία θα είναι δεσμευμένα σε αυτό.
Προσθήκη του RecyclerView στην κύρια διάταξη
Στην ίδια δραστηριότητα, υπάρχει το αρχείο διάταξης main_layout.xml που δημιουργήθηκε για εμάς από προεπιλογή.
Αν διαλέγαμε ένα κενό έργο. Θα έχει δημιουργήσει ένα XML που περιέχει ένα ConstraintLayout και μέσα θα υπάρχει ένα TextView με κείμενο "Hello".
Θα διαγράψουμε όλα τα περιεχόμενα και η διάταξη θα περιέχει μόνο το RecyclerView όπως παρακάτω:
<?xml version="1.0" encoding="utf-8"?> <androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/fruitRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" />
Προσθέσαμε επίσης ένα χαρακτηριστικό id για το RecyclerView το οποίο θα χρησιμοποιήσουμε για να το αναφέρουμε στον κώδικά μας.
android:id="@+id/fruitRecyclerView"
Στη συνέχεια, θα επιστρέψουμε στο αρχείο MainActivity. Χρησιμοποιώντας τα αναγνωριστικά που δημιουργήσαμε, θα μπορέσουμε να αναφερθούμε σε αυτά που μόλις δημιουργήσαμε.
Θα ξεκινήσουμε αναφέροντας το RecyclerView χρησιμοποιώντας τη μέθοδο findViewById() που παρέχεται από Android. Θα το κάνουμε αυτό στη μέθοδο onCreate().
Η μέθοδος onCreate() θα φαίνεται ως εξής.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView) }
Δημιουργήστε ένα ViewHolder
Στη συνέχεια, θα δημιουργήσουμε ένα RecyclerView.ViewHolder το οποίο είναι υπεύθυνο για τη λήψη της Προβολής μας και τη μετατροπή της σε ViewHolder, την οποία το RecyclerView χρησιμοποιεί για να εμφανίσει τα στοιχεία μας.
Θα το κάνουμε αυτό αμέσως μετά τη διασκεδαστική μέθοδο onCreate().
package com.guru99.learnrecycler import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import androidx.recyclerview.widget.RecyclerView class MainActivity : AppCompatActivity() { var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView) } class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView) }
Δημιουργήστε έναν προσαρμογέα RecyclerView
Στη συνέχεια, θα δημιουργήσουμε μια κλάση FruitArrayAdapter που επεκτείνει την κλάση RecyclerView.Adapter.
Ο FruitArrayAdapter που δημιουργούμε θα είναι υπεύθυνος να κάνει τα ακόλουθα.
Θα πάρει ονόματα φρούτων από τη συστοιχία φρούτων. Θα δημιουργήσει ένα ViewHolder χρησιμοποιώντας την προβολή μας one_fruit_view.xml Στη συνέχεια θα συνδέσει το φρούτο σε ένα ViewHolder και θα συνδέσει δυναμικά τα περιεχόμενα στην προβολή που δημιουργήσαμε το one_fruit_view.xml.
package com.guru99.learnrecycler import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import androidx.recyclerview.widget.RecyclerView class MainActivity : AppCompatActivity() { var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView) } class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView) class FruitArrayAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() }
Android Το Studio θα προσθέσει κόκκινα squiggles στον FruitArrayAdapter μας, λέγοντάς μας ότι πρέπει να εφαρμόσουμε μια μέθοδο που μπορεί να χρησιμοποιήσει το RecyclerView για να συνδέσει τον πίνακα μας σε ένα ViewHolder που μπορεί να χρησιμοποιήσει το RecyclerView.
class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder { } override fun getItemCount(): Int { } override fun onBindViewHolder(holder: FruitViewHolder, position: Int) { } }
Θα ξεκινήσουμε με το πιο εύκολο bit από τον κώδικα που δημιουργείται είναι η μέθοδος getItemCount(). Γνωρίζουμε πώς να λάβουμε τον αριθμό των στοιχείων στον πίνακα μας καλώντας τη μέθοδο array.length.
class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder { } override fun getItemCount(): Int { return fruitArray.size } override fun onBindViewHolder(holder: FruitViewHolder, position: Int) { } }
Στη συνέχεια, θα εφαρμόσουμε τη μέθοδο παράκαμψης διασκέδασης στοCreateViewHolder.
Εδώ το RecyclerView μας ζητά να το βοηθήσουμε να δημιουργήσει ένα FruitHolder για αυτό.
Αν θυμηθούμε, έτσι φαινόταν η τάξη μας FruitViewHolder:
class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView)
Απαιτεί το fruitView που δημιουργήσαμε ως αρχείο xml one_fruit_view.xml
Μπορούμε να δημιουργήσουμε μια αναφορά σε αυτό το xml και να το μετατρέψουμε σε Προβολή ως εξής.
class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder { var fruitView = LayoutInflater.from(parent.context).inflate(R.layout.one_fruit_view, parent, false) var fruitViewHolder = FruitViewHolder(fruitView) return fruitViewHolder } override fun getItemCount(): Int { return fruitArray.size } override fun onBindViewHolder(holder: FruitViewHolder, position: Int) { } }
Το υπόλοιπο κομμάτι είναι η παράκαμψη
fun onBindViewHolder(holder: FruitViewHolder, position: Int)
Ο προσαρμογέας RecyclerView.Adapter ζητά με έναν ακέραιο αριθμό θέσης, τον οποίο θα χρησιμοποιήσουμε για να ανακτήσουμε ένα στοιχείο από τη λίστα μας. Μας παρέχει επίσης ένα στήριγμα για να μπορούμε να δεσμεύουμε το αντικείμενο που παίρνουμε από το fruitArray με το View που βρίσκεται μέσα στη θήκη προβολής.
Η προβολή που βρίσκεται μέσα σε ένα ViewHoder είναι προσβάσιμη μέσω του πεδίου ViewHolder.itemView. Μόλις λάβουμε την προβολή, μπορούμε να χρησιμοποιήσουμε το αναγνωριστικό fruitName που δημιουργήσαμε νωρίτερα για να ορίσουμε το περιεχόμενο.
override fun onBindViewHolder(holder: FruitViewHolder, position: Int) { var ourFruitTextView = holder.itemView.findViewById<TextView>(R.id.fruitName) var aFruitName = fruitArray.get(position) ourFruitTextView.setText(aFruitName) }
Με αυτό το FruitArrayAdapter μας είναι ολοκληρωμένο και φαίνεται ως εξής.
class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder { var fruitView = LayoutInflater.from(parent.context).inflate(R.layout.one_fruit_view, parent, false) var fruitViewHolder = FruitViewHolder(fruitView) return fruitViewHolder } override fun getItemCount(): Int { return fruitArray.size } override fun onBindViewHolder(holder: FruitViewHolder, position: Int) { var ourFruitTextView = holder.itemView.findViewById<TextView>(R.id.fruitName) var aFruitName = fruitArray.get(position) ourFruitTextView.setText(aFruitName) } }
Τέλος, είμαστε έτοιμοι να συνδέσουμε τα υπόλοιπα κομμάτια του RecyclerView μας. Τα οποία δημιουργούν ένα LayoutManager, το οποίο θα πει στο RecyclerView πώς να εμφανίζει τα περιεχόμενα της λίστας. Είτε θα εμφανίζεται με γραμμικό τρόπο χρησιμοποιώντας το LinearLayoutManager είτε σε πλέγμα χρησιμοποιώντας GridLayoutManager ή StaggeredGridLayoutManager.
Δημιουργία Layout Manager
Θα επιστρέψουμε στη συνάρτηση onCreate και θα προσθέσουμε το LayoutManager
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView) var fruitLinearLayout = LinearLayoutManager(this) myFruitRecyclerView.layoutManager =fruitLinearLayout }
Συνδέστε τον προσαρμογέα μας σε αντικείμενα και ρυθμίστε τον στο RecyclerView
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView) var fruitLinearLayout = LinearLayoutManager(this) myFruitRecyclerView.layoutManager =fruitLinearLayout var fruitListAdapter = FruitListAdapter(fruitNames) myFruitRecyclerView.adapter =fruitListAdapter }
Έχουμε επίσης δημιουργήσει ένα παράδειγμα fruitListAdapter και του τροφοδοτήσαμε τη σειρά ονομάτων φρούτων.
Και βασικά, τελειώσαμε όλοι.
Το πλήρες αρχείο MainActivity.kt έχει την εξής μορφή.
package com.guru99.learnrecycler import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView class MainActivity : AppCompatActivity() { var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView) var fruitLinearLayout = LinearLayoutManager(this) myFruitRecyclerView.layoutManager =fruitLinearLayout var fruitListAdapter = FruitListAdapter(fruitNames) myFruitRecyclerView.adapter =fruitListAdapter } class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView) class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder { var fruitView = LayoutInflater.from(parent.context).inflate(R.layout.one_fruit_view, parent, false) var fruitViewHolder = FruitViewHolder(fruitView) return fruitViewHolder } override fun getItemCount(): Int { return fruitArray.size } override fun onBindViewHolder(holder: FruitViewHolder, position: Int) { var ourFruitTextView = holder.itemView.findViewById<TextView>(R.id.fruitName) var aFruitName = fruitArray.get(position) ourFruitTextView.setText(aFruitName) } } }