tuomasvaltanen

Untitled

Mar 28th, 2023 (edited)
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.11 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 28.3.2023
  2.  
  3. // Tehdään uusi fragment: CustomViewTesterFragment (mobile_navigation-työkalun kautta) -> laitetaan päävalikkoon -> binding layer käyttöön
  4.  
  5. Esim, CustomViewTesterFragment:
  6.  
  7. class CustomViewTesterFragment : Fragment() {
  8. // change this to match your fragment name
  9. private var _binding: FragmentCustomViewTesterBinding? = null
  10.  
  11. // This property is only valid between onCreateView and
  12. // onDestroyView.
  13. private val binding get() = _binding!!
  14.  
  15. override fun onCreateView(
  16. inflater: LayoutInflater,
  17. container: ViewGroup?,
  18. savedInstanceState: Bundle?
  19. ): View? {
  20. _binding = FragmentCustomViewTesterBinding.inflate(inflater, container, false)
  21. val root: View = binding.root
  22.  
  23. // the binding -object allows you to access views in the layout, textviews etc.
  24.  
  25.  
  26. return root
  27. }
  28.  
  29. override fun onDestroyView() {
  30. super.onDestroyView()
  31. _binding = null
  32. }
  33. }
  34.  
  35. // vaihdetaan ulkoasuksi tähän fragmentiin LinearLayout helppoa testaamista varten
  36.  
  37. <?xml version="1.0" encoding="utf-8"?>
  38. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  39. xmlns:tools="http://schemas.android.com/tools"
  40. android:layout_width="match_parent"
  41. android:layout_height="match_parent"
  42. android:orientation="vertical"
  43. android:layout_margin="5dp"
  44. tools:context=".CustomViewTesterFragment">
  45.  
  46.  
  47. </LinearLayout>
  48.  
  49. // Tehdään uusi kotlin-luokka: CustomTemperatureView:
  50.  
  51. class CustomTemperatureView @JvmOverloads constructor(
  52. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  53. ) : View(context, attrs, defStyleAttr) {
  54.  
  55. init
  56. {
  57. // this is constructor of your component
  58. // all initializations go here
  59. }
  60.  
  61. override fun onDraw(canvas: Canvas) {
  62. super.onDraw(canvas)
  63.  
  64. // here you can do all the drawing
  65. }
  66.  
  67. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  68. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  69.  
  70. // Android uses this to determine the exact size of your component on screen
  71. }
  72. }
  73.  
  74.  
  75. // laitetaan CustomViewTesterFragmentin ulkoasuun XML:n oma custom -komponentti:
  76. // HUOM: paketin nimi on omassa projektissasi eri
  77.  
  78. <com.example.edistynytmobiili2023_21a.CustomTemperatureView
  79. android:id="@+id/customtemperatureview_test"
  80. android:layout_width="wrap_content"
  81. android:layout_height="wrap_content" />
  82.  
  83. // kokeillaan hieman lisää säätää ympyrää ja tekstiä, ei vieläkään kovin hyvä
  84.  
  85. init
  86. {
  87. // define the colors!
  88. paint.color = Color.BLUE
  89. textPaint.color = Color.BLACK
  90. textPaint.textSize = 70f
  91. }
  92.  
  93. // drawing is typically done in the custom view's onDraw-method
  94. override fun onDraw(canvas: Canvas) {
  95. super.onDraw(canvas)
  96.  
  97. // parameters: x-coordinate, y-coordinate, size, color
  98. canvas.drawCircle(100f, 100f, 100f, paint)
  99.  
  100. // parameters: content, x, y, color
  101. canvas.drawText("Test!", 50f, 100f, textPaint);
  102. }
  103.  
  104. // muutetaan onMeasure, jotta voidaan käyttää xml:ssä tarkkoja dp-kokoja
  105.  
  106. class CustomTemperatureView @JvmOverloads constructor(
  107. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  108. ) : View(context, attrs, defStyleAttr) {
  109.  
  110. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  111. private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  112.  
  113. init
  114. {
  115. // define the colors!
  116. paint.color = Color.BLUE
  117. textPaint.color = Color.BLACK
  118. textPaint.textSize = 70f
  119. }
  120.  
  121. // drawing is typically done in the custom view's onDraw-method
  122. override fun onDraw(canvas: Canvas) {
  123. super.onDraw(canvas)
  124.  
  125. // parameters: x-coordinate, y-coordinate, size, color
  126. canvas.drawCircle(100f, 100f, 100f, paint)
  127.  
  128. // parameters: content, x, y, color
  129. canvas.drawText("Test!", 50f, 100f, textPaint);
  130. }
  131.  
  132. // jos ulkoasussa ei anneta tarkkaa kokoa, tämä on default-koko
  133. var size = 200
  134.  
  135. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  136. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  137.  
  138. // Try for a width based on our minimum
  139. val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth
  140. var w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)
  141.  
  142. // if no exact size given (either dp or match_parent)
  143. // use this one instead as default (wrap_content)
  144. if (w == 0)
  145. {
  146. w = size * 2
  147. }
  148.  
  149. // Whatever the width ends up being, ask for a height that would let the view
  150. // get as big as it can
  151. // val minh: Int = View.MeasureSpec.getSize(w) + paddingBottom + paddingTop
  152. // in this case, we use the height the same as our width, since it's a circle
  153. val h: Int = View.resolveSizeAndState(
  154. View.MeasureSpec.getSize(w),
  155. heightMeasureSpec,
  156. 0
  157. )
  158.  
  159. setMeasuredDimension(w, h)
  160. }
  161. }
  162.  
  163. // nyt XML:ssä toimii näin:
  164.  
  165. <com.example.edistynytmobiili2023_21a.CustomTemperatureView
  166. android:id="@+id/customtemperatureview_test"
  167. android:layout_width="200dp"
  168. android:layout_height="200dp" />
  169.  
  170. // vielä hienosäätöä:
  171.  
  172. class CustomTemperatureView @JvmOverloads constructor(
  173. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  174. ) : View(context, attrs, defStyleAttr) {
  175.  
  176. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  177. private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  178.  
  179. init
  180. {
  181. // define the colors!
  182. paint.color = Color.BLUE
  183. textPaint.color = Color.WHITE
  184. textPaint.textSize = 85f
  185. textPaint.textAlign = Paint.Align.CENTER
  186. textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD))
  187. }
  188.  
  189. // drawing is typically done in the custom view's onDraw-method
  190. override fun onDraw(canvas: Canvas) {
  191. super.onDraw(canvas)
  192.  
  193. // parameters: x-coordinate, y-coordinate, size, color
  194. canvas.drawCircle(width.toFloat() / 2, width.toFloat() / 2, width.toFloat() / 2, paint)
  195.  
  196. // parameters: content, x, y, color
  197. canvas.drawText("Test!", width.toFloat() / 2, width.toFloat() / 2 + 24, textPaint);
  198. }
  199.  
  200. // jos ulkoasussa ei anneta tarkkaa kokoa, tämä on default-koko
  201. var size = 200
  202.  
  203. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  204. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  205.  
  206. // Try for a width based on our minimum
  207. val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth
  208. var w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)
  209.  
  210. // if no exact size given (either dp or match_parent)
  211. // use this one instead as default (wrap_content)
  212. if (w == 0)
  213. {
  214. w = size * 2
  215. }
  216.  
  217. // Whatever the width ends up being, ask for a height that would let the view
  218. // get as big as it can
  219. // val minh: Int = View.MeasureSpec.getSize(w) + paddingBottom + paddingTop
  220. // in this case, we use the height the same as our width, since it's a circle
  221. val h: Int = View.resolveSizeAndState(
  222. View.MeasureSpec.getSize(w),
  223. heightMeasureSpec,
  224. 0
  225. )
  226.  
  227. setMeasuredDimension(w, h)
  228. }
  229. }
  230.  
  231. // annetaan mahdollisuus myös vaihtaa lämpötilaa fragmentista:
  232.  
  233. class CustomTemperatureView @JvmOverloads constructor(
  234. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  235. ) : View(context, attrs, defStyleAttr) {
  236.  
  237. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  238. private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  239.  
  240.  
  241. init
  242. {
  243. // define the colors!
  244. paint.color = Color.BLUE
  245. textPaint.color = Color.WHITE
  246. textPaint.textSize = 85f
  247. textPaint.textAlign = Paint.Align.CENTER
  248. textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD))
  249. }
  250.  
  251. // muuttuja, joka pitää kirjaa aktiivisesta lämpötilasta
  252. private var temperature = 0
  253.  
  254. // funktio, joka pystyy muuttamaan aktiviista lämpötilaa esim. fragmentista käsin
  255. fun changeTemperature(temp : Int) {
  256. temperature = temp
  257.  
  258. // muutetaan ympyrän taustaväri lämpötilan perusteella
  259. if(temperature > 0) {
  260. paint.color = Color.RED
  261. }
  262. else {
  263. paint.color = Color.BLUE
  264. }
  265. }
  266.  
  267. // drawing is typically done in the custom view's onDraw-method
  268. override fun onDraw(canvas: Canvas) {
  269. super.onDraw(canvas)
  270.  
  271. // parameters: x-coordinate, y-coordinate, size, color
  272. canvas.drawCircle(width.toFloat() / 2, width.toFloat() / 2, width.toFloat() / 2, paint)
  273.  
  274. // parameters: content, x, y, color
  275. canvas.drawText("${temperature}℃", width.toFloat() / 2, width.toFloat() / 2 + 25, textPaint);
  276. }
  277.  
  278. // jos ulkoasussa ei anneta tarkkaa kokoa, tämä on default-koko
  279. var size = 200
  280.  
  281. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  282. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  283.  
  284. // Try for a width based on our minimum
  285. val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth
  286. var w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)
  287.  
  288. // if no exact size given (either dp or match_parent)
  289. // use this one instead as default (wrap_content)
  290. if (w == 0)
  291. {
  292. w = size * 2
  293. }
  294.  
  295. // Whatever the width ends up being, ask for a height that would let the view
  296. // get as big as it can
  297. // val minh: Int = View.MeasureSpec.getSize(w) + paddingBottom + paddingTop
  298. // in this case, we use the height the same as our width, since it's a circle
  299. val h: Int = View.resolveSizeAndState(
  300. View.MeasureSpec.getSize(w),
  301. heightMeasureSpec,
  302. 0
  303. )
  304.  
  305. setMeasuredDimension(w, h)
  306. }
  307. }
  308.  
  309. // lisätään myös komponentin päivityslogiikka changeTemperatureen:
  310.  
  311. class CustomTemperatureView @JvmOverloads constructor(
  312. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  313. ) : View(context, attrs, defStyleAttr) {
  314.  
  315. // aluastetaan väriobjektit
  316. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  317. private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  318.  
  319. init
  320. {
  321. // define the colors!
  322. paint.color = Color.BLUE
  323. textPaint.color = Color.WHITE
  324. textPaint.textSize = 85f
  325. textPaint.textAlign = Paint.Align.CENTER
  326. textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD))
  327. }
  328.  
  329. // muuttuja, joka pitää kirjaa aktiivisesta lämpötilasta
  330. private var temperature = 0
  331.  
  332. // funktio, joka pystyy muuttamaan aktiviista lämpötilaa esim. fragmentista käsin
  333. fun changeTemperature(temp : Int) {
  334. temperature = temp
  335.  
  336. // muutetaan ympyrän taustaväri lämpötilan perusteella
  337. if(temperature > 0) {
  338. paint.color = Color.RED
  339. }
  340. else {
  341. paint.color = Color.BLUE
  342. }
  343.  
  344. // arvot muuttui, kerrotaan Androidille että piirretään tämä komponentti uudestaan
  345. invalidate()
  346. requestLayout()
  347. }
  348.  
  349. // drawing is typically done in the custom view's onDraw-method
  350. override fun onDraw(canvas: Canvas) {
  351. super.onDraw(canvas)
  352.  
  353. // parameters: x-coordinate, y-coordinate, size, color
  354. canvas.drawCircle(width.toFloat() / 2, width.toFloat() / 2, width.toFloat() / 2, paint)
  355.  
  356. // parameters: content, x, y, color
  357. canvas.drawText("${temperature}℃", width.toFloat() / 2, width.toFloat() / 2 + 25, textPaint);
  358. }
  359.  
  360. // jos ulkoasussa ei anneta tarkkaa kokoa, tämä on default-koko
  361. var size = 200
  362.  
  363. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  364. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  365.  
  366. // Try for a width based on our minimum
  367. val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth
  368. var w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)
  369.  
  370. // if no exact size given (either dp or match_parent)
  371. // use this one instead as default (wrap_content)
  372. if (w == 0)
  373. {
  374. w = size * 2
  375. }
  376.  
  377. // Whatever the width ends up being, ask for a height that would let the view
  378. // get as big as it can
  379. // val minh: Int = View.MeasureSpec.getSize(w) + paddingBottom + paddingTop
  380. // in this case, we use the height the same as our width, since it's a circle
  381. val h: Int = View.resolveSizeAndState(
  382. View.MeasureSpec.getSize(w),
  383. heightMeasureSpec,
  384. 0
  385. )
  386.  
  387. setMeasuredDimension(w, h)
  388. }
  389. }
  390.  
  391. // lisätään XML:ään myös nappi testaamista varten:
  392.  
  393. <com.example.edistynytmobiili2023_21a.CustomTemperatureView
  394. android:id="@+id/customtemperatureview_test"
  395. android:layout_width="120dp"
  396. android:layout_height="120dp" />
  397.  
  398. <Button
  399. android:id="@+id/button_change_temperature"
  400. android:layout_width="match_parent"
  401. android:layout_height="wrap_content"
  402. android:text="CHANGE TEMPERATURE" />
  403.  
  404. // fragmentin onCreateView -> kokeillaan vaihtaa arvoja:
  405.  
  406. // the binding -object allows you to access views in the layout, textviews etc.
  407. binding.customtemperatureviewTest.changeTemperature(7)
  408.  
  409. binding.buttonChangeTemperature.setOnClickListener {
  410. binding.customtemperatureviewTest.changeTemperature(-5)
  411. }
  412.  
  413.  
  414. // nyt komponenttia voi käyttää myös WeatherStation MQTT-datalla, esim. ulkoasuun
  415.  
  416. <com.example.edistynytmobiili2023_21a.CustomTemperatureView
  417. android:id="@+id/customtemperatureview_weatherstation"
  418. android:layout_width="120dp"
  419. android:layout_height="120dp"
  420. app:layout_constraintEnd_toEndOf="parent"
  421. app:layout_constraintStart_toStartOf="parent" />
  422.  
  423.  
  424. // ja MQTT-koodissa (subscribe):
  425.  
  426. activity?.runOnUiThread(java.lang.Runnable {
  427. binding.customtemperatureviewWeatherstation.changeTemperature(temperatureValue.toInt())
  428. })
  429.  
  430. #########################################################
  431. compound controlit, LatestDataView
  432. #########################################################
  433.  
  434. Uusi Kotlin-luokka: LatestDataView
  435.  
  436. class LatestDataView @JvmOverloads constructor(
  437. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  438. ) : LinearLayout(context, attrs, defStyleAttr) {
  439.  
  440. // konstruktori ja alkuarvot
  441. init {
  442.  
  443. }
  444.  
  445. // funktio jonka kautta esim. fragment voi lisätä viestin listaan
  446. fun addData(message : String) {
  447.  
  448. }
  449.  
  450. }
  451.  
  452. // lisätään ensimmäiset ominaisuudet, addDatan kautta voidaan lisätä textViewejä listaan:
  453.  
  454. class LatestDataView @JvmOverloads constructor(
  455. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  456. ) : LinearLayout(context, attrs, defStyleAttr) {
  457.  
  458. // konstruktori ja alkuarvot
  459. init {
  460. this.orientation = VERTICAL
  461.  
  462. addData("Testiviesti 1")
  463. addData("Testiviesti 2")
  464. }
  465.  
  466. // funktio jonka kautta esim. fragment voi lisätä viestin listaan
  467. fun addData(message : String) {
  468. var newTextView : TextView = TextView(context) as TextView
  469. newTextView.setText(message)
  470. newTextView.setBackgroundColor(Color.BLACK)
  471. newTextView.setTextColor(Color.YELLOW)
  472. this.addView(newTextView)
  473. }
  474.  
  475. }
  476.  
  477.  
  478. // asetetaan custom view test fragmenttiin, lisätään myös nappi alle että voidaan lisätä testiviestejä:
  479.  
  480. <com.example.edistynytmobiili2023_21a.LatestDataView
  481. android:id="@+id/latestdataview_test"
  482. android:layout_width="match_parent"
  483. android:layout_height="wrap_content" />
  484.  
  485. <Button
  486. android:id="@+id/button_add_test_message"
  487. android:layout_width="match_parent"
  488. android:layout_height="wrap_content"
  489. android:text="Add message" />
  490.  
  491. // nyt custom view test fragmentissa, kytketään nappi että voidaan testata:
  492.  
  493. // napilla testataan että saadaan uusi viesti LatestDataViewiin
  494. binding.buttonAddTestMessage.setOnClickListener {
  495. var text = UUID.randomUUID().toString()
  496. binding.latestdataviewTest.addData(text)
  497. }
  498.  
  499.  
  500. // tehdään res -> drawable -kansioon uusi xml-tiedosto -> customborder
  501.  
  502. <?xml version="1.0" encoding="UTF-8"?>
  503. <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
  504. <stroke android:width="5dp" android:color="#28de58"/>
  505. </shape>
  506.  
  507. // jotta taustareunus näkyy, lisätään LatestDataViewiin paddingia ja otetaan background käyttöön kyseiselle customborderille
  508.  
  509. <com.example.edistynytmobiili2023_21a.LatestDataView
  510. android:id="@+id/latestdataview_test"
  511. android:background="@drawable/customborder"
  512. android:padding="5dp"
  513. android:layout_width="match_parent"
  514. android:layout_height="wrap_content" />
  515.  
  516.  
  517. // hienosäädetään jotta aloituskorkeus on myös valmiiksi viiden textviewin korkuinen
  518.  
  519. // maksimimäärä rivejä joita lista näyttää
  520. val maxRows = 5
  521.  
  522. // konstruktori ja alkuarvot
  523. init {
  524. this.orientation = VERTICAL
  525.  
  526. // jotta aloituskorkeus saadaan heti alussa viiden TextViewin kokoiseksi (huolimatta siitä
  527. // kuinka monta TextViewiä sisällä on, voidaan tehdä jotain seuraavaa:
  528.  
  529. // tehdään koodin muistiin TextView (jota ei ole tarkoitus käyttää missään) ja otetaan siitä
  530. // yhden TextViewin korkeus näytöllä
  531. var someTextView : TextView = TextView(context)
  532. someTextView.measure(0,0)
  533.  
  534. var rowHeight = someTextView.measuredHeight
  535.  
  536. // otetaan selvää kuinka korkea LinearLayout on alussa näytöllä
  537. this.measure(0, 0)
  538.  
  539. // asetetaan LatestDataViewin aloituskorkeudeksi:
  540. // LinearLayoutin alkukorkeus + 5 * TextViewin korkeus
  541. var additionalHeight = this.measuredHeight + maxRows * rowHeight
  542. this.minimumHeight = additionalHeight
  543.  
  544. }
  545.  
  546. // funktio jonka kautta esim. fragment voi lisätä viestin listaan
  547. fun addData(message : String) {
  548. // niin kauan kuin listassa on enemmän kuin 5 textViewiä, poistetaan
  549. // vanhin textview
  550. while(this.childCount >= maxRows) {
  551. this.removeViewAt(0)
  552. }
  553.  
  554. var newTextView : TextView = TextView(context) as TextView
  555. newTextView.setText(message)
  556. newTextView.setBackgroundColor(Color.BLACK)
  557. newTextView.setTextColor(Color.YELLOW)
  558. this.addView(newTextView)
  559. }
  560.  
  561. // fade in animaatio, res-kansioon uusi kansio -> anim , ja sinne uusi xml -> customfade
  562.  
  563. <?xml version="1.0" encoding="utf-8"?>
  564. <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator">
  565. <alpha
  566. android:duration="2000"
  567. android:fromAlpha="0.1"
  568. android:toAlpha="1.0">
  569. </alpha>
  570. </set>
  571.  
  572. // animaation käyttäminen esim. LatestDataViewissä, kun uutta TextViewiä laitetaan näytölle:
  573.  
  574. // animoidaan uusi TextView fadein-animaatiolla, res -> anim -> customfade
  575. val fadeAnimation: Animation = AnimationUtils.loadAnimation(context, R.anim.customfade)
  576. newTextView.startAnimation(fadeAnimation)
  577.  
  578.  
  579. // jos nyt lisätään WeatherStationFragmentiin uusi LatestDataView tällä id:llä: latestdataview_weather_station
  580.  
  581. // voidaan koodissa kytkeä sääaseman datat siihen kiinni, esim:
  582.  
  583. var timeStamp = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())
  584. var text = "${timeStamp} - Temperature: ${temperatureValue}℃, Humidity: ${item.d.get3().v.toFloat()}%"
  585.  
  586. activity?.runOnUiThread(java.lang.Runnable {
  587. binding.latestdataviewWeatherStation.addData(text)
  588. })
  589.  
  590. // robottianimaatio, kopioi ensin frametiedostot drawableihin, eli esim idle1.png, idle2png jne
  591. // huom: robotanimation.xml tulee drawable-kansion sisälle, ei anim-kansion sisälle
  592.  
  593. <?xml version="1.0" encoding="utf-8"?>
  594. <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
  595. android:oneshot="false">
  596.  
  597. <item
  598. android:duration="70"
  599. android:drawable="@drawable/idle1" />
  600.  
  601. <item
  602. android:duration="70"
  603. android:drawable="@drawable/idle2" />
  604.  
  605. <item
  606. android:duration="70"
  607. android:drawable="@drawable/idle3" />
  608. <!-- ym. loput framet miten haluat -->
  609.  
  610.  
  611. </animation-list>
  612.  
  613. // fragmentin ulkoasuun:
  614.  
  615. <ImageView
  616. android:id="@+id/imageView_robot"
  617. android:layout_width="170dp"
  618. android:layout_height="300dp"
  619. android:background="@drawable/idle1" />
  620.  
  621.  
  622. // fragmentin koodissa, animaation käynnistäminen:
  623.  
  624. binding.imageViewRobot.setBackgroundResource(R.drawable.robotanimation)
  625. val frameAnimation = binding.imageViewRobot.background as AnimationDrawable
  626. frameAnimation.start()
Advertisement
Add Comment
Please, Sign In to add comment