Advertisement
tuomasvaltanen

Untitled

Apr 13th, 2023 (edited)
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.52 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 13.4.2023
  2.  
  3. !!! HOX! CUSTOM VIEWEIHIN LIITTYVÄT MUISTIINPANOT ALEMPANA!!!
  4.  
  5. ###############################
  6. ANDROID-SOVELLUKSEN VIIMEISTELY
  7. ###############################
  8.  
  9. // lokalisaatiot
  10.  
  11. Android Studiossa vasen ylänurkka -> Android-näkymästä -> Project-näkymäksi
  12.  
  13. Tehdään app -> src -> main -> res -kansioon kaksi uutta kansiota:
  14.  
  15. values-en
  16. values-fi
  17.  
  18. Kopioidaan values-kansion strings.xml -tiedostot molempiin kansioihin pohjaksi. Tämän jälkeen clean project ja rebuild project. Tämän jälkeen voit avata minkä tahansa strings.xml -tiedoston, ja klikata oikeasta ylänurkasta Open Editor.
  19.  
  20. Lisätään greeting_text avaimella uusi käännös:
  21.  
  22. Default: Welcome!
  23. English: Welcome!
  24. Finnish: Tervetuloa!
  25.  
  26. Kokeillaan homefragmentin ulkoasussa näyttää tämä viesti:
  27.  
  28. <TextView
  29. android:layout_width="wrap_content"
  30. android:layout_height="wrap_content"
  31. android:layout_margin="20dp"
  32. android:text="@string/greeting_text"
  33. android:textSize="32sp"
  34. app:layout_constraintEnd_toEndOf="parent"
  35. app:layout_constraintStart_toStartOf="parent"
  36. app:layout_constraintTop_toTopOf="parent" />
  37.  
  38.  
  39. // tämän jälkeen tervetuloteksti on joko suomeksi tai englanniksi riippuen puhelimen kielestä.
  40.  
  41. // tehdään myös 10" -tableteille oma layout-kansio => src -> res -> layout-sw720dp.
  42. Kopioidaan fragment_home.xml tähän kansioon pohjaksi.
  43.  
  44. Muutetaan Welcome-teksti isommaksi, eri väriseksi ja kursivoiduksi.
  45.  
  46. <TextView
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:layout_margin="20dp"
  50. android:text="@string/greeting_text"
  51. android:textColor="#9B54D8"
  52. android:textSize="140sp"
  53. android:textStyle="bold|italic"
  54. app:layout_constraintEnd_toEndOf="parent"
  55. app:layout_constraintStart_toStartOf="parent"
  56. app:layout_constraintTop_toTopOf="parent" />
  57.  
  58. Nyt jos kokeilet 10" tabletin emulaattorilla etusivua, näkyy Welcome-teksti erilaisena, koska olemme tehneet isoille tableteille oman täsmäulkoasun.
  59.  
  60. ##############################################
  61. CUSTOM VIEWIEN TEKEMINEN ALUSTA ASTI
  62. ##############################################
  63.  
  64. Omien custom viewien testaamista varten on hyvä tehdä oma testifragment. esim. CustomViewTesterFragment
  65.  
  66. mobile_navigation.xml -> uusi destination -> laitetaan päävalikkoon (menu -> main_activity_drawer, lisätään listaan MainActivity.kt)
  67.  
  68. Otetaan myös binding layer käyttöön tässä fragmentissa.
  69.  
  70. class CustomViewTesterFragment : Fragment() {
  71. // change this to match your fragment name
  72. private var _binding: FragmentCustomViewTesterBinding? = null
  73.  
  74. // This property is only valid between onCreateView and
  75. // onDestroyView.
  76. private val binding get() = _binding!!
  77.  
  78. override fun onCreateView(
  79. inflater: LayoutInflater,
  80. container: ViewGroup?,
  81. savedInstanceState: Bundle?
  82. ): View? {
  83. _binding = FragmentCustomViewTesterBinding.inflate(inflater, container, false)
  84. val root: View = binding.root
  85.  
  86. // the binding -object allows you to access views in the layout, textviews etc.
  87.  
  88. return root
  89. }
  90.  
  91. override fun onDestroyView() {
  92. super.onDestroyView()
  93. _binding = null
  94. }
  95. }
  96.  
  97. ulkoasuun myös linearlayout käyttöön jotta testaaminen on helpompaa:
  98.  
  99. <?xml version="1.0" encoding="utf-8"?>
  100. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  101. xmlns:tools="http://schemas.android.com/tools"
  102. android:layout_width="match_parent"
  103. android:layout_height="match_parent"
  104. xmlns:app="http://schemas.android.com/apk/res-auto"
  105. android:orientation="vertical"
  106. android:layout_margin="10dp"
  107. tools:context=".CustomViewTesterFragment">
  108.  
  109.  
  110. </LinearLayout>
  111.  
  112.  
  113. // Tehdään uusi Kotlin-luokka: CustomTemperatureView
  114.  
  115. class CustomTemperatureView @JvmOverloads constructor(
  116. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  117. ) : View(context, attrs, defStyleAttr) {
  118.  
  119. // your helper variables etc. can be here
  120. init
  121. {
  122. // this is constructor of your component
  123. // all initializations go here
  124. }
  125.  
  126. override fun onDraw(canvas: Canvas) {
  127. super.onDraw(canvas)
  128. // here you can do all the drawing
  129. }
  130.  
  131. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  132. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  133. // Android uses this to determine the exact size of your component on screen
  134. }
  135. }
  136.  
  137. // lisätään valmiiksi komponentti jo ulkoasuun myös:
  138.  
  139. <com.example.android2023tv.CustomTemperatureView
  140. android:layout_width="match_parent"
  141. android:layout_height="match_parent" />
  142.  
  143. HUOM: paketin nimi on omassa projektissasi eri, voi alkaa kirjoittamaan vain CustomTemperatureView xml:ään, ja Android Studio ehdottaa oikeaa nimeä.
  144.  
  145.  
  146. kokeillaan piirtää jotakin
  147.  
  148. class CustomTemperatureView @JvmOverloads constructor(
  149. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  150. ) : View(context, attrs, defStyleAttr) {
  151.  
  152. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  153. private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  154.  
  155. // your helper variables etc. can be here
  156. init {
  157. paint.color = Color.BLUE
  158. textPaint.color = Color.BLACK
  159. }
  160.  
  161. override fun onDraw(canvas: Canvas) {
  162. super.onDraw(canvas)
  163. // you can do all the drawing through the canvas-object
  164. // parameters: x-coordinate, y-coordinate, size, color
  165. canvas.drawCircle(100f, 100f, 100f, paint)
  166.  
  167. // parameters: content, x, y, color
  168. canvas.drawText("Test!", 10f, 10f, textPaint);
  169. }
  170.  
  171. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  172. super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  173. // Android uses this to determine the exact size of your component on screen
  174. }
  175. }
  176.  
  177.  
  178. drawCircle aloittaa piirtämisen ympyrän keskeltä, sen tkaia x ja y on 100f jotta koko ympyrä piirtyy näytölle (kohdassa 0 ja 0 piirtää suuren osan ympyrästä näytön ulkopuolelle.)
  179.  
  180. teksti on myös aivan liian pieni.
  181.  
  182. lisätään onMeasure, jotta CustomView lukee kokotiedot XML:stä, muutetaan XML:
  183.  
  184. <com.example.android2023tv.CustomTemperatureView
  185. android:layout_width="120dp"
  186. android:layout_height="wrap_content" />
  187.  
  188. // CustomView:
  189.  
  190. class CustomTemperatureView @JvmOverloads constructor(
  191. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  192. ) : View(context, attrs, defStyleAttr) {
  193.  
  194. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  195. private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
  196.  
  197. // your helper variables etc. can be here
  198. init {
  199. paint.color = Color.BLUE
  200. textPaint.color = Color.BLACK
  201. textPaint.textSize = 60f
  202. // keskitetään sivusuunnassa
  203. textPaint.textAlign = Paint.Align.CENTER
  204. }
  205.  
  206. // koska nyt on käytössä dynaaminen onMeasure, voidaan
  207. // käyttää width.toFloat() hyödyksi koordinaattien laskemisessa
  208. override fun onDraw(canvas: Canvas) {
  209. super.onDraw(canvas)
  210. // you can do all the drawing through the canvas-object
  211. // parameters: x-coordinate, y-coordinate, size, color
  212. canvas.drawCircle(width.toFloat() / 2, width.toFloat() / 2, width.toFloat() / 2, paint)
  213.  
  214. // parameters: content, x, y, color
  215. canvas.drawText("Test!", width.toFloat() / 2, width.toFloat() / 2, textPaint);
  216. }
  217.  
  218. // oletuskoko viewille, jos käytetään "wrap_content"
  219. val size = 200
  220.  
  221. override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
  222. // Try for a width based on our minimum
  223. val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth
  224. var w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)
  225.  
  226. // if no exact size given (either dp or match_parent)
  227. // use this one instead as default (wrap_content)
  228. if (w == 0)
  229. {
  230. w = size * 2
  231. }
  232.  
  233. // Whatever the width ends up being, ask for a height that would let the view
  234. // get as big as it can
  235. // val minh: Int = View.MeasureSpec.getSize(w) + paddingBottom + paddingTop
  236. // in this case, we use the height the same as our width, since it's a circle
  237. val h: Int = View.resolveSizeAndState(
  238. View.MeasureSpec.getSize(w),
  239. heightMeasureSpec,
  240. 0
  241. )
  242.  
  243. setMeasuredDimension(w, h)
  244. }
  245. }
  246.  
  247. // säädetään vielä lisää:
  248.  
  249. // your helper variables etc. can be here
  250. init {
  251. paint.color = Color.BLUE
  252. textPaint.color = Color.WHITE
  253.  
  254. // muutetaan tekstin koko, lihavointi ja asetetaan sivusuunnassa keskelle
  255. textPaint.textSize = 90f
  256. textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD))
  257. textPaint.textAlign = Paint.Align.CENTER
  258. }
  259.  
  260. // koska nyt on käytössä dynaaminen onMeasure, voidaan
  261. // käyttää width.toFloat() hyödyksi koordinaattien laskemisessa
  262. override fun onDraw(canvas: Canvas) {
  263. super.onDraw(canvas)
  264. // you can do all the drawing through the canvas-object
  265. // parameters: x-coordinate, y-coordinate, size, color
  266. canvas.drawCircle(width.toFloat() / 2, width.toFloat() / 2, width.toFloat() / 2, paint)
  267.  
  268. // parameters: content, x, y, color
  269. // pieni offset y-akseliin, että teksti menee keskelle
  270. // parempi ois koodilla ottaa selvä kuinka korkeaa teksti on ja jakaa se kahdella ja lisätä offsetiksi
  271. canvas.drawText("Test!", width.toFloat() / 2, width.toFloat() / 2 + 26, textPaint);
  272. }
  273.  
  274.  
  275. // kokeillaan testilämpötilalla:
  276.  
  277. canvas.drawText("-32℃", width.toFloat() / 2, width.toFloat() / 2 + 26, textPaint);
  278.  
  279.  
  280. // jotta voidaan keskittää lämpötila muuttujaan, tehdään CustomViewiin luokkatasolle apumuuttuja:
  281.  
  282. private var temperature : Int = 0
  283.  
  284.  
  285. ja kytketään apumuuttuja onDrawiin:
  286.  
  287. canvas.drawText("${temperature}℃", width.toFloat() / 2, width.toFloat() / 2 + 28, textPaint);
  288.  
  289. käytännössä nyt jos muokkaamme temperature-muuttujaa ulkopuolelta, se näkyy myös näytöllä.
  290.  
  291. Tehdään julkinen apufunktio, minkä kautta voidaan lämpötilaa vaihtaa myös fragmentista käsin:
  292.  
  293. // pidetään kirjaa siitä mikä on aktiivinen lämpötila
  294. private var temperature : Int = 0
  295.  
  296. // funktio, mikä asettaa uuden aktiivisen lämpötilan
  297. // esim. fragmentin kautta kutsuttuna
  298. fun changeTemperature(t : Int) {
  299. temperature = t
  300.  
  301. // tiedot muuttui, ilmoitetaan Androidille,
  302. // että pitää piirtää View uudestaan
  303. invalidate()
  304. requestLayout()
  305. }
  306.  
  307. // muutetaan myös väriä lämpötilan vaihtuessa
  308.  
  309. // funktio, mikä asettaa uuden aktiivisen lämpötilan
  310. // esim. fragmentin kautta kutsuttuna
  311. fun changeTemperature(t : Int) {
  312. temperature = t
  313.  
  314. // muutetaan taustaväriä lämpötilan perusteella
  315. if(temperature > 0) {
  316. paint.color = Color.RED
  317. }
  318. else {
  319. paint.color = Color.BLUE
  320. }
  321.  
  322. // tiedot muuttui, ilmoitetaan Androidille,
  323. // että pitää piirtää View uudestaan
  324. invalidate()
  325. requestLayout()
  326. }
  327.  
  328. // lisätään ulkoasuun id customviewille, ja lisätään myös button jossa id
  329.  
  330. <com.example.android2023tv.CustomTemperatureView
  331. android:id="@+id/customtemperatureview_tester"
  332. android:layout_width="120dp"
  333. android:layout_height="wrap_content" />
  334.  
  335. <Button
  336. android:id="@+id/button_change_temperature"
  337. android:layout_width="match_parent"
  338. android:layout_height="wrap_content"
  339. android:text="Button" />
  340.  
  341.  
  342. // kokeillaan asettaa satunnainen lämpötila:
  343.  
  344. // arvotaan Buttonin pohjalta satunnainen lämpötila
  345. binding.buttonChangeTemperature.setOnClickListener {
  346. val temp = Random.nextInt(-50, 50)
  347. binding.customtemperatureviewTester.changeTemperature(temp)
  348. }
  349.  
  350.  
  351. // CustomView on jo aika käyttökelpoinen, kokeillaan esim WeatherStationFragmentissa:
  352.  
  353. ulkoasuun:
  354.  
  355. <com.example.android2023tv.CustomTemperatureView
  356. android:id="@+id/customtemperatureview_weatherstation"
  357. android:layout_width="120dp"
  358. android:layout_height="wrap_content" />
  359.  
  360. Kotlinissa (huom: temperature on sääaseman dataa, lämpötila Double-muodossa):
  361.  
  362. activity?.runOnUiThread {
  363. binding.customtemperatureviewWeatherstation.changeTemperature(temperature.toInt())
  364. }
  365.  
  366. ##################################
  367. COMPOUND CONTROL - LatestDataView
  368. ##################################
  369.  
  370. Tehdään uusi Kotlin-luokka projektiin, nimeltään LatestDataView, ja otetaan sopiva pohja Moodlesta:
  371.  
  372. class LatestDataView @JvmOverloads constructor(
  373. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  374. ) : LinearLayout(context, attrs, defStyleAttr) {
  375.  
  376. // rest of the basic methods here from the template above
  377. }
  378.  
  379. huom: ei tarvitse tehdä itse onDraw, onMeasure ym. koska ne ovat jo LinearLayoutissa valmiina
  380.  
  381. // lisätään lisää funktioita:
  382.  
  383. class LatestDataView @JvmOverloads constructor(
  384. context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  385. ) : LinearLayout(context, attrs, defStyleAttr) {
  386. // rest of the basic methods here from the template above
  387. init {
  388. // asetetaan LinearLayout ylhäältä alas (oletus horizontal)
  389. this.orientation = VERTICAL
  390. }
  391.  
  392. // apufunktio, jonka kautta esim. fragment voi lisätä uuden
  393. // TextViewin / viestin listaan
  394. fun addData(message: String) {
  395.  
  396. }
  397. }
  398.  
  399. // lisätään ulkoasuun testimielessä (muista clean project ja rebuild project jos ei meinaa toimia aluksi)
  400. // lisätään myös nappi testaamista varten
  401.  
  402. <com.example.android2023tv.LatestDataView
  403. android:id="@+id/latestDataView_tester"
  404. android:layout_width="match_parent"
  405. android:layout_height="wrap_content"
  406. android:layout_marginTop="30dp" />
  407.  
  408. <Button
  409. android:id="@+id/button_add_data_test"
  410. android:layout_width="match_parent"
  411. android:layout_height="wrap_content"
  412. android:text="ADD DATA" />
  413.  
  414. // kokeillaan fragmentin koodissa lisätä satunnainen teksti listaan
  415.  
  416. // lisätään joku random string listaan
  417. binding.buttonAddDataTest.setOnClickListener {
  418. var text = UUID.randomUUID().toString()
  419. binding.latestDataViewTester.addData(text)
  420. }
  421.  
  422. // tehdään drawable-kansioon uusi tiedosto: customborder.xml
  423.  
  424. <?xml version="1.0" encoding="UTF-8"?>
  425. <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
  426. <padding android:left="4dp" android:right="4dp" android:top="4dp" android:bottom="4dp"/>
  427. <stroke android:width="4dp" android:color="#6ECA45"/>
  428. </shape>
  429.  
  430. asetetaan LatestDataViewiin taustakuvaksi XML:ssä:
  431.  
  432. <com.example.android2023tv.LatestDataView
  433. android:id="@+id/latestDataView_tester"
  434. android:background="@drawable/customborder"
  435. android:layout_width="match_parent"
  436. android:layout_height="wrap_content"
  437. android:layout_marginTop="30dp" />
  438.  
  439.  
  440.  
  441. // estetään ettei listaan tule yli 5 TextViewiä:
  442.  
  443. // maksimirivien määrä listassa
  444. val maxRows = 5
  445.  
  446. // rest of the basic methods here from the template above
  447. init {
  448. // asetetaan LinearLayout ylhäältä alas (oletus horizontal)
  449. this.orientation = VERTICAL
  450. }
  451.  
  452. // apufunktio, jonka kautta esim. fragment voi lisätä uuden
  453. // TextViewin / viestin listaan
  454. fun addData(message: String) {
  455.  
  456. // niin kauan kuin listassa on liikaa TextViewejä:
  457. // poista vanhin TextView
  458. while(this.childCount >= maxRows) {
  459. this.removeViewAt(0)
  460. }
  461.  
  462. // lisätään uusi TextView listaan
  463. var newTextView : TextView = TextView(context) as TextView
  464. newTextView.setText(message)
  465. newTextView.setBackgroundColor(Color.BLACK)
  466. newTextView.setTextColor(Color.YELLOW)
  467. this.addView(newTextView)
  468. }
  469.  
  470. // jos halutaan että LatestDataViewillä on oikea korkeus heti alussa (5x TextView + borderin korkeus), voidaan tehdä näin:
  471.  
  472. // rest of the basic methods here from the template above
  473. init {
  474. // asetetaan LinearLayout ylhäältä alas (oletus horizontal)
  475. this.orientation = VERTICAL
  476.  
  477. // jotta LatestDataView ei olisi heti alussa läjässä (koska korkeus on 0)
  478. // muutetaan LatestDataViewin korkeus koodin avulla viiden TextViewin korkuiseksi
  479.  
  480. // tehdään yksi TextView muistiin (tätä ei laiteta mihinkään näkyville, vaan tästä lasketaan
  481. // yhden TextViewin korkeus TÄMÄN PUHELIMEN NÄYTÖLLÄ
  482. var someTextView : TextView = TextView(context)
  483.  
  484. // pyydetään Androidia mittaamaan tämän TextViewin koko, JOS SE OLISI näytöllä
  485. // jos tämä jätetään pois, muistissa olevan TextViewin korkeus on silloin vain 0
  486. someTextView.measure(0,0)
  487.  
  488. // yhden TextViewin korkeus on siten tämä
  489. var rowHeight = someTextView.measuredHeight
  490.  
  491. // mitataan myös itse LinearLayout (esim. borderin takia)
  492. this.measure(0,0)
  493.  
  494. // LinearLayoutin alkukorkeus on siten tämä (borderin takia)
  495. var additionalHeight = this.measuredHeight
  496.  
  497. // asetetaan LinearLayoutilla aloituskorkeus, johon mahtuu tasan viisi TextViewiä
  498. // eli kaava = yhden TextViewin korkeus * 5 + LinearLayoutin korkeus alussa
  499. this.minimumHeight = rowHeight * maxRows + additionalHeight
  500.  
  501. }
  502.  
  503.  
  504. // kokeillaan myös simppeliä fade-in animaatiota. tee projektin res-kansioon uusi kansio:
  505. anim
  506.  
  507. ja tee sinne uusi tiedosto
  508.  
  509. customfade.xml
  510.  
  511. sisällöksi (käytännössä kytketään alpha-kanavaan 2sek animaatio, joka nostaa viewin näkyvyydeen 10%:sta 100%:iin):
  512.  
  513. <?xml version="1.0" encoding="utf-8"?>
  514. <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator">
  515. <alpha
  516. android:duration="2000"
  517. android:fromAlpha="0.1"
  518. android:toAlpha="1.0">
  519. </alpha>
  520. </set>
  521.  
  522. // Kotlinissa pitää ottaa vielä käyttöön tämä animaatio
  523.  
  524. // juuri ennen kuin TextView lisätään näkyviin:
  525.  
  526. // haetaan res -> anim -> customfade.xml animaatio
  527. // ja kytketään se TextViewiin -> käynnistetään animaatio
  528. val fadeAnimation : Animation = AnimationUtils.loadAnimation(context, R.anim.customfade)
  529. newTextView.startAnimation(fadeAnimation)
  530.  
  531.  
  532. // tässä vaiheessa komponentti on aika pitkälle valmis, voidaan kytketä esim. myös säädataan:
  533.  
  534. // tehdään viesti, aikaleima + lämpötila + humidity
  535. var time = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())
  536. var message = "${time} - Temperature: ${temperature}℃, humidity: ${humidity}%"
  537.  
  538. // varmistetaan tällä se, että binding-layeria käsitellään varmasti UI-threadista
  539. // joissain tapauksissa MQTT-koodi ajetaan tausta-threadissa, jolloin binding-layerin
  540. // käyttäminen voi tiltata
  541. activity?.runOnUiThread {
  542.  
  543. binding.latestDataViewTemperatures.addData(message)
  544. }
  545.  
  546. // frame-animaatiot, demo: robotti
  547.  
  548. drawable kansioon uusi tiedosto: robotanimation (kuvatiedostot tehtävänannon linkistä):
  549.  
  550. <?xml version="1.0" encoding="utf-8"?>
  551. <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
  552. android:oneshot="false">
  553.  
  554. <item
  555. android:duration="100"
  556. android:drawable="@drawable/idle1"/>
  557.  
  558. <item
  559. android:duration="100"
  560. android:drawable="@drawable/idle2"/>
  561.  
  562. .... jne ....
  563.  
  564. </animation-list>
  565.  
  566. // lisätään johonkin fragmentiin ImageView:
  567.  
  568. <ImageView
  569. android:id="@+id/imageview_robot"
  570. android:layout_width="220dp"
  571. android:layout_height="400dp"
  572. android:layout_marginBottom="30dp"
  573. android:background="@drawable/robotanimation"
  574. app:layout_constraintBottom_toBottomOf="parent"
  575. app:layout_constraintEnd_toEndOf="parent"
  576. app:layout_constraintStart_toStartOf="parent" />
  577.  
  578. // Kotlinissa:
  579.  
  580. // käynnistetään animaatio
  581. val mImageViewFilling: ImageView = binding.imageviewRobot
  582. (mImageViewFilling.background as AnimationDrawable).start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement