Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edistynyt mobiiliohjelmointi, 30.3.2023
- RecyclerView tarvitsee erillisen lisäulkoasun yksittäistä dataitemiä varten, esim yksittäinne kommentti.
- res -> layout -> recycler_view_item.xml
- Ulkoasulle on hyvä antaa pieni korkeus, ettei yksi kommentti vie koko näyttöä:
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="120dp">
- </androidx.constraintlayout.widget.ConstraintLayout>
- // esim. ohjeen kuvan mukainen ulkoasu (suurinpiirtein)
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
- android:layout_height="120dp">
- <TextView
- android:id="@+id/textView_comment_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Kommentin nimi"
- android:textColor="#3B6CC1"
- android:textStyle="bold"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- <TextView
- android:id="@+id/textView_comment_email"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Kommentin email"
- android:textColor="#8A3EC1"
- android:textStyle="bold|italic"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- <TextView
- android:id="@+id/textView_comment_body"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Kommentin body"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/textView_comment_name" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- // CommentAdapter.kt, pohja, josta puuttuu datan ja viewien kytkeminen toisiinsa
- // aloitetaan luomalla uusi luokka CommentHolder
- class CommentAdapter(private val comments: List<Comment>) : RecyclerView.Adapter<CommentAdapter.CommentHolder>() {
- // tähän väliin tulee kaikki RecyclerView-adapterin vaatimat metodit
- // kuten onCreateViewHolder, onBindViewHolder sekä getItemCount
- // binding layerin muuttujien alustaminen
- private var _binding: RecyclerViewItemBinding? = null
- private val binding get() = _binding!!
- // ViewHolderin onCreate-metodi. käytännössä tässä kytketään binding layer
- // osaksi CommentHolder-luokkaan (adapterin sisäinen luokka)
- // koska CommentAdapter pohjautuu RecyclerViewin perusadapteriin, täytyy tästä
- // luokasta löytyä metodi nimeltä onCreateViewHolder
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommentHolder {
- // binding layerina toimii yksitätinen recyclerview_item_row.xml -instanssi
- _binding = RecyclerViewItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
- return CommentHolder(binding)
- }
- // tämä metodi kytkee yksittäisen Comment-objektin yksittäisen CommentHolder-instanssiin
- // koska CommentAdapter pohjautuu RecyclerViewin perusadapteriin, täytyy tästä
- // luokasta löytyä metodi nimeltä onBindViewHolder
- override fun onBindViewHolder(holder: CommentHolder, position: Int) {
- val itemComment = comments[position]
- holder.bindComment(itemComment)
- }
- // Adapterin täytyy pysty tietämään sisältämänsä datan koko tämän metodin avulla
- // koska CommentAdapter pohjautuu RecyclerViewin perusadapteriin, täytyy tästä
- // luokasta löytyä metodi nimeltä getItemCount
- override fun getItemCount(): Int {
- return comments.size
- }
- // CommentHolder, joka määritettiin oman CommentAdapterin perusmäärityksessä (ks. luokan yläosa)
- // Holder-luokka sisältää logiikan, jolla data ja ulkoasu kytketään toisiinsa
- class CommentHolder(v: RecyclerViewItemBinding) : RecyclerView.ViewHolder(v.root), View.OnClickListener {
- // tämän kommentin ulkoasu ja varsinainen data
- private var view: RecyclerViewItemBinding = v
- private var comment: Comment? = null
- // mahdollistetaan yksittäisen itemin klikkaaminen tässä luokassa
- init {
- }
- // metodi, joka kytkee datan yksityiskohdat ulkoasun yksityiskohtiin
- fun bindComment(comment : Comment)
- {
- }
- // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodio
- override fun onClick(v: View) {
- }
- }
- }
- // CommentHolder, kytketään viewit dataan, esim:
- class CommentHolder(v: RecyclerViewItemBinding) : RecyclerView.ViewHolder(v.root), View.OnClickListener {
- // tämän kommentin ulkoasu ja varsinainen data
- private var view: RecyclerViewItemBinding = v
- private var comment: Comment? = null
- // mahdollistetaan yksittäisen itemin klikkaaminen tässä luokassa
- init {
- // tämä mahdollistaa sen, että kun kommenttia klikataan
- // suoritetaan alta löytyvä onClick
- v.root.setOnClickListener(this)
- }
- // metodi, joka kytkee datan yksityiskohdat ulkoasun yksityiskohtiin
- fun bindComment(comment : Comment)
- {
- // laitetaan yksittäinen comment-data talteen myöhempää käyttöä varten
- // ks. onClick
- this.comment = comment
- // asetetaan eli "mäpätään" jokainen kommentin data
- // sopivaan viewiin
- view.textViewCommentName.text = comment.name
- view.textViewCommentEmail.text = comment.email
- view.textViewCommentBody.text = comment.body
- }
- // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodio
- override fun onClick(v: View) {
- }
- }
- fragment_comment_data.xml, eli fragmentti jossa haetaan ja muutetaan Comment-dataa rajapinnasta: lisätään RecyclerView ulkoasuun:
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/recyclerViewComments"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- Viimeinen vaihe, eli kytketään CommentDataFragmentin koodissa recyclerview ja data.
- 1. lisätään fragmentin luokkatasolle adapteri ja layout managerin muuttujat:
- // alustetaan viittaus adapteriin sekä luodaan LinearLayoutManager
- // RecyclerView tarvitsee jonkin LayoutManagerin, joista yksinkertaisin on Linear
- private lateinit var adapter: CommentAdapter
- private lateinit var linearLayoutManager: LinearLayoutManager
- 2. onCreateView, rakennetaan ja kytketään linear layout manager:
- // luodaan linear layout manager ja kytketään se ulkoasussa olevaan RecyclerViewiin
- // tarkista että recyclerviewin id: täsmää binding-layerin koodin kanssa
- linearLayoutManager = LinearLayoutManager(context)
- binding.recyclerViewComments.layoutManager = linearLayoutManager
- 3. Volley-koodissa, kun data on saatu ladattua ja muutettua Kotlin muotoon, luodaan ja kytketään adapteri
- // luodaan adapteri omalla datalla, ja kytketään adapteri recyclerviewiin
- adapter = CommentAdapter(rows)
- binding.recyclerViewComments.adapter = adapter
- --------------
- Hienosäätöjä:
- --------------
- Osa nimistä ja emaileista menee päällekkäin, kokeillaan lyhentää nimeä jos on yli 20 merkkiä!
- // metodi, joka kytkee datan yksityiskohdat ulkoasun yksityiskohtiin
- fun bindComment(comment : Comment)
- {
- // laitetaan yksittäinen comment-data talteen myöhempää käyttöä varten
- // ks. onClick
- this.comment = comment
- // asetetaan eli "mäpätään" jokainen kommentin datasopivaan viewiin
- // tallennetaan kommentin nimi muuttujaan
- var text : String = comment.name.toString()
- // jos pituus on yli 20 merkkiä, lyhennä nimeä muuttujassa ja laita kolme pistettä perään
- if(text.length > 20) {
- text = text.substring(0, 20) + "..."
- }
- // aseta muuttujassa oleva nimi textViewiin
- view.textViewCommentName.text = text
- view.textViewCommentEmail.text = comment.email
- view.textViewCommentBody.text = comment.body
- }
- // CommentAdapter, onClick ja siirtyminen toiseen fragmenttiin
- // Tehdään uusi fragment mobile navigationin kautta: CommentDetailFragment. Ota käyttöön binding-layer tässä uudessa fragmentissa.
- // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodi, testataan
- override fun onClick(v: View) {
- Log.d("TESTI", "RecyclerView-Comment -klikattu!")
- Log.d("TESTI", "Commentin ID = " + comment?.id.toString())
- }
- // CommentDetailFragment.kt, lähtökohta miten jatkaa:
- class CommentDetailFragment : Fragment() {
- private var _binding: FragmentCommentDetailBinding? = null
- // get fragment parameters from previous fragment
- val args: CommentDetailFragmentArgs by navArgs()
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentCommentDetailBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // print out the given parameter into logs
- Log.d("TESTI", "Kommentin id-parametri: " + args.id.toString())
- // tästä eteenpäin detail fragmentin voi tehdä pääpiirteittäin kolmella eri tavalla
- // detail fragmentin idea tässä tapauksessa on ottaa vastaan tai hakea yhden kommentin datat
- // ja asettaa ne esim. erillisiin TextVieweihin (tee itse TextViewit tämän fragmentin ulkoasuun)
- // ja kytke ne haluamallasi tavalla
- // vaihtoehto 1: lähetetään Detail fragmentiin pelkkä kommentin id
- // idea on se että rakennetaan uusi URL/osoite rajapintaan, ja haetaan vain yksi kommentti
- // vaihtoehto 2: lähetetään detail fragmentiin kaikki kommentin muuttujat omina argumentteinaan
- // ja tulostetaan ne sellaisenaan. hyvä puoli: helppo ratkaisu, huono puoli: jos data kerkeää muuttua
- // välissä rajapinnassa data-palvelussa, silloin mobiilisovellus näyttää vanhentunutta dataa
- // vaihtoehto 3: lähetetään detail fragmentiin JSON-muodossa oleva Comment-objekti, ja puretaan
- // se tässä fragmentissa GSONin avulla Comment-objektiksi
- // jos mennään vaihtoehdolla 1, saadaan aina ajantasaisin data rajapinnasta
- // tätä varten tarvitaan generoitu yhden kommentin URL/osoite, joka voidaan hakea, esim:
- // this is the url where we want to get our data from
- val JSON_URL = "https://jsonplaceholder.typicode.com/comments/" + args.id
- Log.d("TESTI", JSON_URL)
- // tätä JSON_URLia hyödyntämällä, lataa Volley-koodilla raakadata, ja muuta se
- // GSONilla objektimuotoon:
- // var item : TodoItem = gson.fromJson(response, TodoItem::class.java)
- // tämän jälkeen item-muuttujan avulla, asetetaan arvot minne halutaan:
- // binding.jokutextview.text = item.email jne.
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement