Advertisement
tuomasvaltanen

Untitled

Mar 30th, 2023 (edited)
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.84 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 30.3.2023
  2.  
  3. RecyclerView tarvitsee erillisen lisäulkoasun yksittäistä dataitemiä varten, esim yksittäinne kommentti.
  4.  
  5. res -> layout -> recycler_view_item.xml
  6.  
  7. Ulkoasulle on hyvä antaa pieni korkeus, ettei yksi kommentti vie koko näyttöä:
  8.  
  9. <?xml version="1.0" encoding="utf-8"?>
  10. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  11. android:layout_width="match_parent"
  12. android:layout_height="120dp">
  13.  
  14. </androidx.constraintlayout.widget.ConstraintLayout>
  15.  
  16.  
  17. // esim. ohjeen kuvan mukainen ulkoasu (suurinpiirtein)
  18.  
  19. <?xml version="1.0" encoding="utf-8"?>
  20. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  21. xmlns:app="http://schemas.android.com/apk/res-auto"
  22. xmlns:tools="http://schemas.android.com/tools"
  23. android:layout_width="match_parent"
  24. android:layout_height="120dp">
  25.  
  26. <TextView
  27. android:id="@+id/textView_comment_name"
  28. android:layout_width="wrap_content"
  29. android:layout_height="wrap_content"
  30. android:layout_margin="10dp"
  31. android:text="Kommentin nimi"
  32. android:textColor="#3B6CC1"
  33. android:textStyle="bold"
  34. app:layout_constraintStart_toStartOf="parent"
  35. app:layout_constraintTop_toTopOf="parent" />
  36.  
  37. <TextView
  38. android:id="@+id/textView_comment_email"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:layout_margin="10dp"
  42. android:text="Kommentin email"
  43. android:textColor="#8A3EC1"
  44. android:textStyle="bold|italic"
  45. app:layout_constraintEnd_toEndOf="parent"
  46. app:layout_constraintTop_toTopOf="parent" />
  47.  
  48. <TextView
  49. android:id="@+id/textView_comment_body"
  50. android:layout_width="wrap_content"
  51. android:layout_height="wrap_content"
  52. android:layout_margin="10dp"
  53. android:text="Kommentin body"
  54. app:layout_constraintStart_toStartOf="parent"
  55. app:layout_constraintTop_toBottomOf="@+id/textView_comment_name" />
  56. </androidx.constraintlayout.widget.ConstraintLayout>
  57.  
  58.  
  59. // CommentAdapter.kt, pohja, josta puuttuu datan ja viewien kytkeminen toisiinsa
  60.  
  61. // aloitetaan luomalla uusi luokka CommentHolder
  62. class CommentAdapter(private val comments: List<Comment>) : RecyclerView.Adapter<CommentAdapter.CommentHolder>() {
  63. // tähän väliin tulee kaikki RecyclerView-adapterin vaatimat metodit
  64. // kuten onCreateViewHolder, onBindViewHolder sekä getItemCount
  65.  
  66. // binding layerin muuttujien alustaminen
  67. private var _binding: RecyclerViewItemBinding? = null
  68. private val binding get() = _binding!!
  69.  
  70. // ViewHolderin onCreate-metodi. käytännössä tässä kytketään binding layer
  71. // osaksi CommentHolder-luokkaan (adapterin sisäinen luokka)
  72. // koska CommentAdapter pohjautuu RecyclerViewin perusadapteriin, täytyy tästä
  73. // luokasta löytyä metodi nimeltä onCreateViewHolder
  74. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommentHolder {
  75. // binding layerina toimii yksitätinen recyclerview_item_row.xml -instanssi
  76. _binding = RecyclerViewItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
  77. return CommentHolder(binding)
  78. }
  79.  
  80. // tämä metodi kytkee yksittäisen Comment-objektin yksittäisen CommentHolder-instanssiin
  81. // koska CommentAdapter pohjautuu RecyclerViewin perusadapteriin, täytyy tästä
  82. // luokasta löytyä metodi nimeltä onBindViewHolder
  83. override fun onBindViewHolder(holder: CommentHolder, position: Int) {
  84. val itemComment = comments[position]
  85. holder.bindComment(itemComment)
  86. }
  87.  
  88. // Adapterin täytyy pysty tietämään sisältämänsä datan koko tämän metodin avulla
  89. // koska CommentAdapter pohjautuu RecyclerViewin perusadapteriin, täytyy tästä
  90. // luokasta löytyä metodi nimeltä getItemCount
  91. override fun getItemCount(): Int {
  92. return comments.size
  93. }
  94.  
  95. // CommentHolder, joka määritettiin oman CommentAdapterin perusmäärityksessä (ks. luokan yläosa)
  96. // Holder-luokka sisältää logiikan, jolla data ja ulkoasu kytketään toisiinsa
  97. class CommentHolder(v: RecyclerViewItemBinding) : RecyclerView.ViewHolder(v.root), View.OnClickListener {
  98.  
  99. // tämän kommentin ulkoasu ja varsinainen data
  100. private var view: RecyclerViewItemBinding = v
  101. private var comment: Comment? = null
  102.  
  103. // mahdollistetaan yksittäisen itemin klikkaaminen tässä luokassa
  104. init {
  105.  
  106. }
  107.  
  108. // metodi, joka kytkee datan yksityiskohdat ulkoasun yksityiskohtiin
  109. fun bindComment(comment : Comment)
  110. {
  111.  
  112. }
  113.  
  114. // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodio
  115. override fun onClick(v: View) {
  116.  
  117. }
  118. }
  119.  
  120. }
  121.  
  122. // CommentHolder, kytketään viewit dataan, esim:
  123.  
  124. class CommentHolder(v: RecyclerViewItemBinding) : RecyclerView.ViewHolder(v.root), View.OnClickListener {
  125.  
  126. // tämän kommentin ulkoasu ja varsinainen data
  127. private var view: RecyclerViewItemBinding = v
  128. private var comment: Comment? = null
  129.  
  130. // mahdollistetaan yksittäisen itemin klikkaaminen tässä luokassa
  131. init {
  132. // tämä mahdollistaa sen, että kun kommenttia klikataan
  133. // suoritetaan alta löytyvä onClick
  134. v.root.setOnClickListener(this)
  135. }
  136.  
  137. // metodi, joka kytkee datan yksityiskohdat ulkoasun yksityiskohtiin
  138. fun bindComment(comment : Comment)
  139. {
  140. // laitetaan yksittäinen comment-data talteen myöhempää käyttöä varten
  141. // ks. onClick
  142. this.comment = comment
  143.  
  144. // asetetaan eli "mäpätään" jokainen kommentin data
  145. // sopivaan viewiin
  146. view.textViewCommentName.text = comment.name
  147. view.textViewCommentEmail.text = comment.email
  148. view.textViewCommentBody.text = comment.body
  149. }
  150.  
  151. // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodio
  152. override fun onClick(v: View) {
  153.  
  154. }
  155. }
  156.  
  157. fragment_comment_data.xml, eli fragmentti jossa haetaan ja muutetaan Comment-dataa rajapinnasta: lisätään RecyclerView ulkoasuun:
  158.  
  159. <androidx.recyclerview.widget.RecyclerView
  160. android:id="@+id/recyclerViewComments"
  161. android:layout_width="match_parent"
  162. android:layout_height="match_parent" />
  163.  
  164.  
  165. Viimeinen vaihe, eli kytketään CommentDataFragmentin koodissa recyclerview ja data.
  166.  
  167. 1. lisätään fragmentin luokkatasolle adapteri ja layout managerin muuttujat:
  168.  
  169. // alustetaan viittaus adapteriin sekä luodaan LinearLayoutManager
  170. // RecyclerView tarvitsee jonkin LayoutManagerin, joista yksinkertaisin on Linear
  171. private lateinit var adapter: CommentAdapter
  172. private lateinit var linearLayoutManager: LinearLayoutManager
  173.  
  174. 2. onCreateView, rakennetaan ja kytketään linear layout manager:
  175.  
  176. // luodaan linear layout manager ja kytketään se ulkoasussa olevaan RecyclerViewiin
  177. // tarkista että recyclerviewin id: täsmää binding-layerin koodin kanssa
  178. linearLayoutManager = LinearLayoutManager(context)
  179. binding.recyclerViewComments.layoutManager = linearLayoutManager
  180.  
  181. 3. Volley-koodissa, kun data on saatu ladattua ja muutettua Kotlin muotoon, luodaan ja kytketään adapteri
  182.  
  183. // luodaan adapteri omalla datalla, ja kytketään adapteri recyclerviewiin
  184. adapter = CommentAdapter(rows)
  185. binding.recyclerViewComments.adapter = adapter
  186.  
  187.  
  188. --------------
  189. Hienosäätöjä:
  190. --------------
  191.  
  192. Osa nimistä ja emaileista menee päällekkäin, kokeillaan lyhentää nimeä jos on yli 20 merkkiä!
  193.  
  194. // metodi, joka kytkee datan yksityiskohdat ulkoasun yksityiskohtiin
  195. fun bindComment(comment : Comment)
  196. {
  197. // laitetaan yksittäinen comment-data talteen myöhempää käyttöä varten
  198. // ks. onClick
  199. this.comment = comment
  200.  
  201. // asetetaan eli "mäpätään" jokainen kommentin datasopivaan viewiin
  202.  
  203. // tallennetaan kommentin nimi muuttujaan
  204. var text : String = comment.name.toString()
  205.  
  206. // jos pituus on yli 20 merkkiä, lyhennä nimeä muuttujassa ja laita kolme pistettä perään
  207. if(text.length > 20) {
  208. text = text.substring(0, 20) + "..."
  209. }
  210.  
  211. // aseta muuttujassa oleva nimi textViewiin
  212. view.textViewCommentName.text = text
  213. view.textViewCommentEmail.text = comment.email
  214. view.textViewCommentBody.text = comment.body
  215. }
  216.  
  217.  
  218. // CommentAdapter, onClick ja siirtyminen toiseen fragmenttiin
  219. // Tehdään uusi fragment mobile navigationin kautta: CommentDetailFragment. Ota käyttöön binding-layer tässä uudessa fragmentissa.
  220.  
  221. // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodi, testataan
  222. override fun onClick(v: View) {
  223. Log.d("TESTI", "RecyclerView-Comment -klikattu!")
  224. Log.d("TESTI", "Commentin ID = " + comment?.id.toString())
  225.  
  226.  
  227. }
  228.  
  229. // CommentDetailFragment.kt, lähtökohta miten jatkaa:
  230.  
  231. class CommentDetailFragment : Fragment() {
  232. private var _binding: FragmentCommentDetailBinding? = null
  233.  
  234. // get fragment parameters from previous fragment
  235. val args: CommentDetailFragmentArgs by navArgs()
  236.  
  237. // This property is only valid between onCreateView and
  238. // onDestroyView.
  239. private val binding get() = _binding!!
  240. override fun onCreateView(
  241. inflater: LayoutInflater,
  242. container: ViewGroup?,
  243. savedInstanceState: Bundle?
  244. ): View? {
  245. _binding = FragmentCommentDetailBinding.inflate(inflater, container, false)
  246. val root: View = binding.root
  247.  
  248. // print out the given parameter into logs
  249. Log.d("TESTI", "Kommentin id-parametri: " + args.id.toString())
  250.  
  251. // tästä eteenpäin detail fragmentin voi tehdä pääpiirteittäin kolmella eri tavalla
  252. // detail fragmentin idea tässä tapauksessa on ottaa vastaan tai hakea yhden kommentin datat
  253. // ja asettaa ne esim. erillisiin TextVieweihin (tee itse TextViewit tämän fragmentin ulkoasuun)
  254. // ja kytke ne haluamallasi tavalla
  255.  
  256. // vaihtoehto 1: lähetetään Detail fragmentiin pelkkä kommentin id
  257. // idea on se että rakennetaan uusi URL/osoite rajapintaan, ja haetaan vain yksi kommentti
  258.  
  259. // vaihtoehto 2: lähetetään detail fragmentiin kaikki kommentin muuttujat omina argumentteinaan
  260. // ja tulostetaan ne sellaisenaan. hyvä puoli: helppo ratkaisu, huono puoli: jos data kerkeää muuttua
  261. // välissä rajapinnassa data-palvelussa, silloin mobiilisovellus näyttää vanhentunutta dataa
  262.  
  263. // vaihtoehto 3: lähetetään detail fragmentiin JSON-muodossa oleva Comment-objekti, ja puretaan
  264. // se tässä fragmentissa GSONin avulla Comment-objektiksi
  265.  
  266. // jos mennään vaihtoehdolla 1, saadaan aina ajantasaisin data rajapinnasta
  267. // tätä varten tarvitaan generoitu yhden kommentin URL/osoite, joka voidaan hakea, esim:
  268.  
  269. // this is the url where we want to get our data from
  270. val JSON_URL = "https://jsonplaceholder.typicode.com/comments/" + args.id
  271. Log.d("TESTI", JSON_URL)
  272.  
  273. // tätä JSON_URLia hyödyntämällä, lataa Volley-koodilla raakadata, ja muuta se
  274. // GSONilla objektimuotoon:
  275. // var item : TodoItem = gson.fromJson(response, TodoItem::class.java)
  276.  
  277. // tämän jälkeen item-muuttujan avulla, asetetaan arvot minne halutaan:
  278. // binding.jokutextview.text = item.email jne.
  279.  
  280. return root
  281. }
  282. override fun onDestroyView() {
  283. super.onDestroyView()
  284. _binding = null
  285. }
  286. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement