Advertisement
tuomasvaltanen

Untitled

Feb 6th, 2023 (edited)
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.68 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 6.2.2023
  2.  
  3. // hienosäätöjä, lyhennettään kommentin nimeä jos liian pitkä, CommentHolder::
  4.  
  5. fun bindComment(comment : Comment)
  6. {
  7. // otetaan kommentti talteen ylätasolle, että voimme käyttää sitä myös esim. onClickissä
  8. this.comment = comment
  9.  
  10. // tallennetaan kommentin nimi Stringiksi
  11. var commentName : String = comment.name as String
  12.  
  13. // jos kommentin nimi on yli 20 merkkiä,
  14. // lyhennetään se 20:een merkkiin ja lisätään kolme pistettä
  15. if(commentName.length > 20)
  16. {
  17. commentName = commentName.substring(0, 20) + "..."
  18. }
  19.  
  20. // oli kommentin nimi mitä tahansa, asetetaan se käyttöliittymään
  21. view.textViewCommentName.text = commentName
  22.  
  23. // asetetaan muut tiedot ulkoasuun
  24. view.textViewCommentEmail.text = comment.email
  25. view.textViewCommentBody.text = comment.body
  26. }
  27.  
  28.  
  29. // RecyclerView, itemin klikkaaminen ja siirtyminen toiseen fragmentiin
  30. // tätä varten on tehty ApiDetailFragment
  31.  
  32. // tarkista että seuraava on asetettu init:iin, jotta
  33. // onClick ylipäätänsä toimii
  34. init {
  35. v.root.setOnClickListener(this)
  36. }
  37.  
  38.  
  39. // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodio
  40. override fun onClick(v: View) {
  41. Log.d("ADVTECH", "RecyclerView CLICK!!! " + comment?.id.toString())
  42.  
  43. // muutetaan Int? => Int
  44. val commentId = comment?.id as Int
  45.  
  46. // navigoidaan ApiFragmentista -> ApiDetailFragment, parametrina kommentin id
  47. val action = ApiFragmentDirections.actionApiFragmentToApiDetailFragment(commentId)
  48. v.findNavController().navigate(action)
  49. }
  50.  
  51.  
  52. // ApiDetailFragmentissa voidaan ottaa muuttuja vastaan
  53.  
  54. class ApiDetailFragment : Fragment() {
  55. private var _binding: FragmentApiDetailBinding? = null
  56.  
  57. // get fragment parameters from previous fragment
  58. val args: DataDetailFragmentArgs by navArgs()
  59.  
  60. // This property is only valid between onCreateView and
  61. // onDestroyView.
  62. private val binding get() = _binding!!
  63. override fun onCreateView(
  64. inflater: LayoutInflater,
  65. container: ViewGroup?,
  66. savedInstanceState: Bundle?
  67. ): View? {
  68. _binding = FragmentApiDetailBinding.inflate(inflater, container, false)
  69. val root: View = binding.root
  70. // print out the given parameter into logs
  71.  
  72. Log.d("ADVTECH", "ID = " + args.id.toString())
  73.  
  74. val JSON_URL = "https://jsonplaceholder.typicode.com/comments/" + args.id.toString()
  75. Log.d("ADVTECH", JSON_URL)
  76.  
  77. // Tästä eteenpäin datan voi hakea kolmella tavalla:
  78.  
  79. // 1. Käydä id:tä URLin muodostamisessa (ks. ylempää JSON_URL) ja hae Volleylla sen avulla
  80. // pelkästään kyseisen id:n takana oleva kommenttidata (yksittäinen JSON-objekti)
  81. // huomaa tässä tapauksessa että GSON -muunnoksessa pitää käyttää yhden objektin esimerkkiä
  82. // var item : Comment = gson.fromJson(response, Comment::class.java)
  83.  
  84. // hyvät puolet: aina ajantasainen data
  85. // huono puoli: enemmän koodia
  86.  
  87. // 2. laita fragmenttien välille lisää parametreja (esim. kommentin id, name, email, body jne)
  88. // ja aseta nämä argumentit suoraan omiin TextVieweihin ApiDetailFragmentin koodissa
  89.  
  90. // hyvät puolet: yksinkertainen koodi, huomattavasti vähemmän tietoliikennettä
  91. // huono puoli: data voi olla vanhentunut
  92.  
  93. // 3. muuta koko comment-olio aiemmassa fragmentissa JSON-formaattiin, ja siirrä vain
  94. // JSON-muuttuja tähän fragmenttiin
  95.  
  96. // hyvät ja huonot puolet samat kuin vaihtoehdossa 2, mutta lisäksi vaatii GSON-muunnoksen
  97. // molemmissa fragmenteissa
  98. // ApiFragment -> comment-olio -> JSON ..... ja myöhemmin ApiDetailFragment: JSON -> comment-olio
  99.  
  100. return root
  101. }
  102.  
  103. override fun onDestroyView() {
  104. super.onDestroyView()
  105. _binding = null
  106. }
  107. }
  108.  
  109. // Google MapsFragment, xml-ulkoasu
  110.  
  111. // Siirretään MapsFragment ConstraintLayoutin sisälle, että voidaan laittaa lisää
  112. // Viewejä kartan päälle
  113.  
  114. // HUOM: attribuutti "tools:layout="@layout/fragment_home" avulla
  115. // XML-virhe poistuu (unknown fragments), koska asetamme ulkoasueditoria varten
  116. // placeholderiksi home-fragmentin
  117.  
  118. <?xml version="1.0" encoding="utf-8"?>
  119. <androidx.constraintlayout.widget.ConstraintLayout
  120. xmlns:android="http://schemas.android.com/apk/res/android"
  121. xmlns:tools="http://schemas.android.com/tools"
  122. android:layout_width="match_parent"
  123. android:layout_height="match_parent"
  124. tools:context=".MapsFragment">
  125. <fragment
  126. android:id="@+id/map"
  127. android:name="com.google.android.gms.maps.SupportMapFragment"
  128. android:layout_width="match_parent"
  129. android:layout_height="match_parent"
  130. tools:layout="@layout/fragment_home" />
  131. </androidx.constraintlayout.widget.ConstraintLayout>
  132.  
  133.  
  134. // MapsFragment, lisätään binding-layer
  135.  
  136. class MapsFragment : Fragment() {
  137.  
  138. // change this to match your fragment name
  139. private var _binding: FragmentMapsBinding? = null
  140.  
  141. // This property is only valid between onCreateView and
  142. // onDestroyView.
  143. private val binding get() = _binding!!
  144.  
  145. private val callback = OnMapReadyCallback { googleMap ->
  146. /**
  147. * Manipulates the map once available.
  148. * This callback is triggered when the map is ready to be used.
  149. * This is where we can add markers or lines, add listeners or move the camera.
  150. * In this case, we just add a marker near Sydney, Australia.
  151. * If Google Play services is not installed on the device, the user will be prompted to
  152. * install it inside the SupportMapFragment. This method will only be triggered once the
  153. * user has installed Google Play services and returned to the app.
  154. */
  155. val sydney = LatLng(-34.0, 151.0)
  156. googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
  157.  
  158. val rovaniemi = LatLng(66.50352001528042, 25.727189822733095)
  159. googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
  160.  
  161. // newLatLngZoomin avulla voidaan siirtää kameraa ja myös zoomata
  162. googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
  163. }
  164.  
  165. override fun onCreateView(
  166. inflater: LayoutInflater,
  167. container: ViewGroup?,
  168. savedInstanceState: Bundle?
  169. ): View? {
  170. _binding = FragmentMapsBinding.inflate(inflater, container, false)
  171. val root: View = binding.root
  172.  
  173. return root
  174. }
  175.  
  176. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  177. super.onViewCreated(view, savedInstanceState)
  178. val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
  179. mapFragment?.getMapAsync(callback)
  180. }
  181. }
  182.  
  183.  
  184. // MapsFragment, xml, lisätään CheckBox
  185.  
  186. <?xml version="1.0" encoding="utf-8"?>
  187. <androidx.constraintlayout.widget.ConstraintLayout
  188. xmlns:android="http://schemas.android.com/apk/res/android"
  189. xmlns:app="http://schemas.android.com/apk/res-auto"
  190. xmlns:tools="http://schemas.android.com/tools"
  191. android:layout_width="match_parent"
  192. android:layout_height="match_parent"
  193. tools:context=".MapsFragment">
  194. <fragment
  195. android:id="@+id/map"
  196. android:name="com.google.android.gms.maps.SupportMapFragment"
  197. android:layout_width="match_parent"
  198. android:layout_height="match_parent"
  199. tools:layout="@layout/fragment_home" />
  200.  
  201. <CheckBox
  202. android:id="@+id/checkBox_zoom_controls"
  203. android:layout_width="wrap_content"
  204. android:layout_height="wrap_content"
  205. android:layout_margin="10dp"
  206. android:text="Zoom ON/OFF"
  207. app:layout_constraintStart_toStartOf="parent"
  208. app:layout_constraintTop_toTopOf="parent" />
  209. </androidx.constraintlayout.widget.ConstraintLayout>
  210.  
  211. // MapsFragment, otetaan googleMap-olio talteen että pääsemme siihen käsiksi muualla luokassa
  212. // esim. checkboxit ja radiobuttonit
  213.  
  214. class MapsFragment : Fragment() {
  215.  
  216. // change this to match your fragment name
  217. private var _binding: FragmentMapsBinding? = null
  218.  
  219. // This property is only valid between onCreateView and
  220. // onDestroyView.
  221. private val binding get() = _binding!!
  222.  
  223. private val callback = OnMapReadyCallback { googleMap ->
  224.  
  225. // laitetaan googleMap-olio talteen luokan tasolle (gMap)
  226. gMap = googleMap
  227.  
  228. val sydney = LatLng(-34.0, 151.0)
  229. googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
  230.  
  231. val rovaniemi = LatLng(66.50352001528042, 25.727189822733095)
  232. googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
  233.  
  234. // newLatLngZoomin avulla voidaan siirtää kameraa ja myös zoomata
  235. googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
  236. }
  237.  
  238. // jotta pääsemme käsiksi googleMap-objektiin myöhemmin
  239. private lateinit var gMap : GoogleMap
  240.  
  241. override fun onCreateView(
  242. inflater: LayoutInflater,
  243. container: ViewGroup?,
  244. savedInstanceState: Bundle?
  245. ): View? {
  246. _binding = FragmentMapsBinding.inflate(inflater, container, false)
  247. val root: View = binding.root
  248.  
  249. binding.checkBoxZoomControls.setOnCheckedChangeListener { compoundButton, b ->
  250.  
  251. }
  252.  
  253. return root
  254. }
  255.  
  256. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  257. super.onViewCreated(view, savedInstanceState)
  258. val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
  259. mapFragment?.getMapAsync(callback)
  260. }
  261. }
  262.  
  263. // MapsFragment XML, lisätään RadioGroup + Radiobuttoneita
  264.  
  265. <?xml version="1.0" encoding="utf-8"?>
  266. <androidx.constraintlayout.widget.ConstraintLayout
  267. xmlns:android="http://schemas.android.com/apk/res/android"
  268. xmlns:app="http://schemas.android.com/apk/res-auto"
  269. xmlns:tools="http://schemas.android.com/tools"
  270. android:layout_width="match_parent"
  271. android:layout_height="match_parent"
  272. tools:context=".MapsFragment">
  273. <fragment
  274. android:id="@+id/map"
  275. android:name="com.google.android.gms.maps.SupportMapFragment"
  276. android:layout_width="match_parent"
  277. android:layout_height="match_parent"
  278. tools:layout="@layout/fragment_home" />
  279.  
  280. <CheckBox
  281. android:id="@+id/checkBox_zoom_controls"
  282. android:layout_width="wrap_content"
  283. android:layout_height="wrap_content"
  284. android:layout_margin="10dp"
  285. android:text="Zoom ON/OFF"
  286. app:layout_constraintStart_toStartOf="parent"
  287. app:layout_constraintTop_toTopOf="parent" />
  288.  
  289. <RadioGroup
  290. android:layout_width="wrap_content"
  291. android:layout_height="wrap_content"
  292. android:layout_margin="10dp"
  293. app:layout_constraintEnd_toEndOf="parent"
  294. app:layout_constraintTop_toTopOf="parent">
  295.  
  296. <RadioButton
  297. android:id="@+id/radioButton_normal_map"
  298. android:layout_width="match_parent"
  299. android:layout_height="wrap_content"
  300. android:checked="true"
  301. android:text="Normal" />
  302.  
  303. <RadioButton
  304. android:id="@+id/radioButton_hybrid_map"
  305. android:layout_width="match_parent"
  306. android:layout_height="wrap_content"
  307. android:text="Hybrid" />
  308. </RadioGroup>
  309. </androidx.constraintlayout.widget.ConstraintLayout>
  310.  
  311.  
  312.  
  313. // lisätään myös RadioButtonit koodiin, MapsFragment.kt
  314.  
  315. override fun onCreateView(
  316. inflater: LayoutInflater,
  317. container: ViewGroup?,
  318. savedInstanceState: Bundle?
  319. ): View? {
  320. _binding = FragmentMapsBinding.inflate(inflater, container, false)
  321. val root: View = binding.root
  322.  
  323. // kun checkboxia klikataan -> zoom-kontrollit päälle tai pois
  324. binding.checkBoxZoomControls.setOnCheckedChangeListener { compoundButton, b ->
  325. gMap.uiSettings.isZoomControlsEnabled = b
  326. }
  327.  
  328. // radio button -> muutetaan kartan tyyppi VAIN SILLOIN, jos
  329. // radio button on valittu (oletuksena setOnChecked käynnistyy molemmissa
  330. // tapauksissa, eli on tai off, mikä tuo bugeja tähän tilanteeseen)
  331. binding.radioButtonNormalMap.setOnCheckedChangeListener { compoundButton, b ->
  332. if(compoundButton.isChecked) {
  333. gMap.mapType = GoogleMap.MAP_TYPE_NORMAL
  334. }
  335. }
  336.  
  337. // ... ja sama hybrid-kartalle
  338. binding.radioButtonHybridMap.setOnCheckedChangeListener { compoundButton, b ->
  339. if(compoundButton.isChecked) {
  340. gMap.mapType = GoogleMap.MAP_TYPE_HYBRID
  341. }
  342. }
  343.  
  344.  
  345.  
  346. return root
  347. }
  348.  
  349.  
  350. // Lisätään MapsFragmentiin ONMarkerClick -tuki:
  351.  
  352. class MapsFragment : Fragment(), GoogleMap.OnMarkerClickListener {
  353.  
  354. // lisätään vaadittava funktio MapsFragmentin pohjalle:
  355.  
  356. // jos mitä tahansa markeria klikataan, ajetaan tämä funktio
  357. override fun onMarkerClick(p0: Marker): Boolean {
  358. Log.d("ADVTECH", "MARKKERI!")
  359.  
  360. // onMarkerClick vaatii lopussa että palautetaan boolean
  361. return false
  362. }
  363.  
  364. // lisää myös tämä OnMapReadyCallbackiin, esim. gMap = googleMap -kohdan jälkeen:
  365.  
  366. // käytetään MapsFragmentissa olevaa onMarkerClick-funktiota
  367. // käytetään MapsFragmentissa olevaa onMarkerClick-funktiota
  368. // jos markeria klikataan
  369. googleMap.setOnMarkerClickListener(this)
  370.  
  371.  
  372. // Markereihin voi lisätä myös dataa tageilla:
  373.  
  374. private val callback = OnMapReadyCallback { googleMap ->
  375. // laitetaan googleMap-olio talteen luokan tasolle (gMap)
  376. gMap = googleMap
  377.  
  378. // käytetään MapsFragmentissa olevaa onMarkerClick-funktiota
  379. // jos markeria klikataan
  380. googleMap.setOnMarkerClickListener(this)
  381.  
  382. // asetetaan markerit muuttujiin, jotta saamme
  383. // asettaa niihin omaa dataa mukaan tagin avulla
  384. // tässä tapauksessa kaupungin nimi
  385. val sydney = LatLng(-34.0, 151.0)
  386. var marker1 : Marker? = googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
  387. marker1?.tag = "Sydney"
  388.  
  389. val rovaniemi = LatLng(66.50352001528042, 25.727189822733095)
  390. var marker2 : Marker? = googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
  391. marker2?.tag = "Rovaniemi"
  392.  
  393. // newLatLngZoomin avulla voidaan siirtää kameraa ja myös zoomata
  394. googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
  395. }
  396.  
  397.  
  398. // markerin datat voidaan ottaa onMarkerClickissä vastaan näin:
  399.  
  400. // jos mitä tahansa markeria klikataan, ajetaan tämä funktio
  401. override fun onMarkerClick(p0: Marker): Boolean {
  402. Log.d("ADVTECH", "MARKKERI!")
  403.  
  404. // lokitetaan/tulostetaan markeriin liitetyt koordinaatit sekä
  405. // tagi, jossa pitäisi olla kaupungin nimi
  406. Log.d("ADVTECH", p0.position.latitude.toString())
  407. Log.d("ADVTECH", p0.position.longitude.toString())
  408. Log.d("ADVTECH", p0.tag.toString())
  409.  
  410. // onMarkerClick vaatii lopussa että palautetaan boolean
  411. return false
  412. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement