Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edistynyt mobiiliohjelmointi, 10.2.2023
- CommentAdapter -> bindComment
- // viilataan kommentin nimeä hieman lyhemmäksi ettei mene päällekkäin emailin kanssa
- fun bindComment(comment : Comment)
- {
- this.comment = comment
- // asetetaan oikeat datat oikeaan kohtaan
- // ulkoasussa
- view.textViewCommentEmail.text = comment.email.toString()
- // jos kommentin nimi on liian pitkä -> lyhennetään ja perään kolme pistettä
- var commentName : String = comment.name.toString()
- if(commentName.length > 20){
- commentName = commentName.substring(0, 20) + "..."
- }
- // asetetaan muut tiedot ulkoasuun
- view.textViewCommentName.text = commentName
- view.textViewCommentBody.text = comment.body.toString()
- }
- CommentHolderissa, onClick:
- // jos itemiä klikataan käyttöliittymässä, ajetaan tämä koodio
- override fun onClick(v: View) {
- // koska bindCommentissa tallennettiin aktiivinen comment-olio talteen
- // saamme näppärästi comment-oliosta haettua klikatun kommentin id:n ja muut tiedot
- Log.d("TESTI", "RecyclerView CLICK! " + comment?.id.toString())
- // tätä varten tulee tehdä CommentDetailFragment navigaatioeditorin kautta.
- // lisää action CommentApiFragmentista CommentDetailFragmentiin, ja
- // CommentDetailFragmentiin argumentti id, tyyppiä Int ja oletusarvo - 1
- val action = CommentApiFragmentDirections.actionCommentApiFragmentToCommentDetailFragment(comment?.id as Int)
- v.findNavController().navigate(action)
- }
- // CommentDetailFragment, esim.
- class CommentDetailFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentCommentDetailBinding? = null
- 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
- Log.d("TESTI", "id:" + args.id.toString())
- // the binding -object allows you to access views in the layout, textviews etc.
- // rakennetaan id-argumentin avulla uusi JSON_URL, VOLLLEYTÄ VARTEN
- // toisin sanoen, URL viittaa yksittäiseen kommenttiin rajapinnassa id:n perusteella
- val JSON_URL = "https://jsonplaceholder.typicode.com/comments/" + args.id.toString()
- Log.d("TESTI", JSON_URL)
- // pääasiassa kolme eri lähestymistapaa, miten jatkaa tästä:
- // VAIHTOEHTO 1: ota vastaan pelkkä klikattu id (kuten tässä nyt), ja hae sitä vastaava
- // data Volleylla uudestaan. Huom: koska nyt haetaan vain yhden kommentin data kerrallaan,
- // käytetään GSONin osalta yksinkertaisempaa versiota, esim.
- // var item : Comment = gson.fromJson(response, Comment::class.java)
- // tämän jälkeen asetetaan dataa ulkoasuun miten halutaan esim.
- // binding.jokutextview.text = item.name.toString() jne.
- // hyvät puolet: aina ajantasainen data
- // huonot puolet: enemmän koodia, enemmän tietoliikennettä
- // VAIHTOEHTO 2: lähetä edellisestä fragmentista lisää argumentteja, eli kaikki muutkin
- // yhden kommentin tiedot (nimi, email, body jne)
- // hyvät puolet: helppo koodata / vähän koodia
- // huonot puolet: data saattaa olla vanhentunut. jos data-luokassa on paljon kenttiä,
- // argumenttien määrä kasvaa suureksi
- // VAIHTOEHTO 3: lähetä edellisestä fragmentista koko comment-olio JSON-formaatissa (käytä GSONia)
- // tässä detail-fragmentissa, pura JSON takaisin Kotlin-olioksi.
- // hyvät puolet: suurikaan määrä argumentteja ei haittaa, koska kaikki on vain yhdessä JSONissa
- // huonot puolet: data saattaa olla vanhentunut, vaatii hieman lisää koodia GSONin osalta
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // ------------------------------------------
- // Harjoitus 2 - Google Maps
- // ------------------------------------------
- Luo ensin Google Maps API key, ks. ohje Moodlessa. Google Maps ei toimi Androidissa ilman voimassa olevaa API keytä.
- Luo navigaatioeditorin kautta uusi fragment (Google Maps Fragment), ja laita se päävalikkoon (res -> menu -> activity_main_drawer.xml sekä MainActivity.kt)
- Gradle Scripts -> local.properties-tiedosto:
- Lisää tänne uusi muuttuja nimeltä MAPS_API_KEY, johon asetetaan oma Google MAPS API key. ALLA OLEVA ESIMERKKI EI OLE OIKEA API KEY:
- MAPS_API_KEY=AIzfdsÖFKLHDLFJKaFJHDJHKFGDSHsFJKHDSKLJGhfjldaghlrieah
- AndroidManifest.xml -> kytketään MAPS_API_KEY -muuttuja tällä tavalla:
- <meta-data
- android:name="com.google.android.geo.API_KEY"
- android:value="${MAPS_API_KEY}" />
- MapsFragment:
- class MapsFragment : Fragment() {
- // tämä callback ajetaan silloin, kun Google Maps on ladattu
- // fragmenttiin onnistuneesti
- private val callback = OnMapReadyCallback { googleMap ->
- val sydney = LatLng(-34.0, 151.0)
- googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
- val rovaniemi = LatLng(66.50336579596632, 25.727513206740678)
- googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
- // siirretään alkunäkymä
- googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
- }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return inflater.inflate(R.layout.fragment_maps, container, false)
- }
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- mapFragment?.getMapAsync(callback)
- }
- }
- // otetaan binding layer käyttöön:
- class MapsFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentMapsBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- // tämä callback ajetaan silloin, kun Google Maps on ladattu
- // fragmenttiin onnistuneesti
- private val callback = OnMapReadyCallback { googleMap ->
- val sydney = LatLng(-34.0, 151.0)
- googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
- val rovaniemi = LatLng(66.50336579596632, 25.727513206740678)
- googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
- // siirretään alkunäkymä
- googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
- }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentMapsBinding.inflate(inflater, container, false)
- val root: View = binding.root
- return root
- }
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- mapFragment?.getMapAsync(callback)
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // MapsFragmentin ulkoasu xml:, muokataan jotta saadaan ConstraintLayoutin sisälle kartta, jotta
- // voimme lisätä uusia ominaisuuksia kartan päälle:
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:context=".MapsFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <fragment
- android:id="@+id/map"
- android:name="com.google.android.gms.maps.SupportMapFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- // Jotta pääsemme eroon "Unknown fragments" -ongelmasta, joka estää meitä käyttämästä Design-näkymään, lisää fragment-tagiin:
- tools:layout="@layout/fragment_home"
- ... eli kokonaisuudessaan nyt (lisätty myös contraintit):
- <?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"
- tools:context=".MapsFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <fragment
- android:id="@+id/map"
- android:name="com.google.android.gms.maps.SupportMapFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:layout="@layout/fragment_home" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- // lisätään CheckBox ulkoasuun:
- <CheckBox
- android:id="@+id/checkBox_zoom_controls"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Zoom ON/OFF"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- // MapsFragment, otetaan googleMaps-olio talteen, jotta voimme käsitellä sitä muualtakin
- class MapsFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentMapsBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- // jotta pääsemme googleMap-olioon muualtakin käsiksi:
- private lateinit var gMap : GoogleMap
- // tämä callback ajetaan silloin, kun Google Maps on ladattu
- // fragmenttiin onnistuneesti
- private val callback = OnMapReadyCallback { googleMap ->
- // asetetaan googleMap -olio talteen ylätasolla (luokkaan jäsenmuuttujaksi)
- gMap = googleMap
- val sydney = LatLng(-34.0, 151.0)
- googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
- val rovaniemi = LatLng(66.50336579596632, 25.727513206740678)
- googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
- // siirretään alkunäkymä
- googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
- }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentMapsBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // checkboxin event handler -> zoom-kontrollit joko päälle tai pois
- binding.checkBoxZoomControls.setOnCheckedChangeListener { compoundButton, b ->
- gMap.uiSettings.isZoomControlsEnabled = b
- }
- return root
- }
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- mapFragment?.getMapAsync(callback)
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // Zoom-controllit jäävät email-painikkeen alle, res -> layout -> app_bar_main.xml , asetetaan FloatingActionButton piiloon:
- android:visibility="invisible"
- // maps fragment layout xml:, lisätään RadioGroup + RadioButtonit 2 kpl
- <?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"
- tools:context=".MapsFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <fragment
- android:id="@+id/map"
- android:name="com.google.android.gms.maps.SupportMapFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:layout="@layout/fragment_home" />
- <CheckBox
- android:id="@+id/checkBox_zoom_controls"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:text="Zoom ON/OFF"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- <RadioGroup
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent">
- <RadioButton
- android:id="@+id/radioButton_normal_map"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:checked="true"
- android:text="Normal" />
- <RadioButton
- android:id="@+id/radioButton_hybrid_map"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Hybrid" />
- </RadioGroup>
- </androidx.constraintlayout.widget.ConstraintLayout>
- // MapsFragment.kt -> lisätään radiobuttonit:
- class MapsFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentMapsBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- // jotta pääsemme googleMap-olioon muualtakin käsiksi:
- private lateinit var gMap : GoogleMap
- // tämä callback ajetaan silloin, kun Google Maps on ladattu
- // fragmenttiin onnistuneesti
- private val callback = OnMapReadyCallback { googleMap ->
- // asetetaan googleMap -olio talteen ylätasolla (luokkaan jäsenmuuttujaksi)
- gMap = googleMap
- val sydney = LatLng(-34.0, 151.0)
- googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
- val rovaniemi = LatLng(66.50336579596632, 25.727513206740678)
- googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
- // siirretään alkunäkymä
- googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
- }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentMapsBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // checkboxin event handler -> zoom-kontrollit joko päälle tai pois
- binding.checkBoxZoomControls.setOnCheckedChangeListener { compoundButton, b ->
- gMap.uiSettings.isZoomControlsEnabled = b
- }
- // radio button 1, tarvitsemme if-lauseen tarkistamaan että valinta on päällä, koska muuten
- // radiobuttonit "tappelevat" keskenään kumpi karttatyyppi on nyt oikeasti päällä
- // huom: tämä funktio käynnistyy molempiin suuntiin, eli kun valinta laitetaan päälle tai otetaan pois
- binding.radioButtonNormalMap.setOnCheckedChangeListener { compoundButton, b ->
- if(compoundButton.isChecked) {
- gMap.mapType = GoogleMap.MAP_TYPE_NORMAL
- }
- }
- // radio button 2
- binding.radioButtonHybridMap.setOnCheckedChangeListener { compoundButton, b ->
- if(compoundButton.isChecked) {
- gMap.mapType = GoogleMap.MAP_TYPE_HYBRID
- }
- }
- return root
- }
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- mapFragment?.getMapAsync(callback)
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // MapsFragment, onMarkerClick eli kun markkeria klikataan, lisätään tuki:
- class MapsFragment : Fragment(), GoogleMap.OnMarkerClickListener {
- // change this to match your fragment name
- private var _binding: FragmentMapsBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- // jotta pääsemme googleMap-olioon muualtakin käsiksi:
- private lateinit var gMap : GoogleMap
- // tämä callback ajetaan silloin, kun Google Maps on ladattu
- // fragmenttiin onnistuneesti
- private val callback = OnMapReadyCallback { googleMap ->
- // asetetaan googleMap -olio talteen ylätasolla (luokkaan jäsenmuuttujaksi)
- gMap = googleMap
- // tallennetaan Sydneyn ja Rovaniemen markkerit muuttujiin, jotta voimme laittaa dataa
- // mukaan tagin avulla. tag löytyy kaikista Androidin View-tyyppisistä olioista!
- val sydney = LatLng(-34.0, 151.0)
- var marker1 : Marker? = googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
- marker1?.tag = "Sydney"
- val rovaniemi = LatLng(66.50336579596632, 25.727513206740678)
- var marker2 : Marker? = googleMap.addMarker(MarkerOptions().position(rovaniemi).title("Rovaniemi!"))
- marker2?.tag = "Rovaniemi"
- // siirretään alkunäkymä
- googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(rovaniemi, 15f))
- // asetetaan että tämä luokka (MapsFragment) hoitaa Marker-klikkaukset
- // ks. alimmaisena oleva OnMarkerClickListener
- googleMap.setOnMarkerClickListener(this)
- }
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentMapsBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // checkboxin event handler -> zoom-kontrollit joko päälle tai pois
- binding.checkBoxZoomControls.setOnCheckedChangeListener { compoundButton, b ->
- gMap.uiSettings.isZoomControlsEnabled = b
- }
- // radio button 1
- binding.radioButtonNormalMap.setOnCheckedChangeListener { compoundButton, b ->
- if(compoundButton.isChecked) {
- gMap.mapType = GoogleMap.MAP_TYPE_NORMAL
- }
- }
- // radio button 2
- binding.radioButtonHybridMap.setOnCheckedChangeListener { compoundButton, b ->
- if(compoundButton.isChecked) {
- gMap.mapType = GoogleMap.MAP_TYPE_HYBRID
- }
- }
- return root
- }
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- mapFragment?.getMapAsync(callback)
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- // OnMarkerClickiä kutsutaan jos mitä tahansa markeria kartalla klikataan
- override fun onMarkerClick(p0: Marker): Boolean {
- Log.d("TESTI", "MARKKERI CLICK! JES!")
- // kaivetaan marker-oliosta klikatun markkerin nimi ja koordinaatit
- Log.d("TESTI", p0.tag.toString())
- Log.d("TESTI", p0.position.latitude.toString())
- Log.d("TESTI", p0.position.longitude.toString())
- // OnMarkerClick vaatii että lopuksi palautetaan Boolean
- return false
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement