· 6 years ago · Nov 29, 2019, 02:42 PM
1. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project (Slika 1) izabrati Empty Activity i kliknuti na Next
23. Unutar Configure your project prozora unijeti sljedeće: • Name: "Zivotni ciklus aktivnosti" • Package name: "com.example.zivotniciklusaktivnosti" • podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE
3Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga.
4
56. Modifikovati MainActivity da prikaže pop-up poruku svaki put kad aktivnost prođe kroz neku od faza životnog ciklusa:
6
7
87. Izvršiti aplikaciju na emulatoru/uređaju. Treba da se vidi sekvenca: Kreiranje(onCreate) - Startovanje (onStart) - Nastavak (onResume). 8. Kliknuti na dugme „back“. Treba da se vidi sekvenca: Pauza (onPause) - Stop (onStop) - Završetak (onDestroy). 9. Startovati ponovo aplikaciju. Treba da se ponovo vidi sekvenca: Kreiranje(onCreate) - Startovanje (onStart) - Nastavak (onResume). 10. Kliknuti na dugme „home“ (dugme u sredini). Treba da se vidi sekvenca: Pauza (onPause) - Stop (onStop). 11. Vratiti se u aplikaciju. Treba da se vidi sekvenca: Restartovanje (onRestart) - Startovanje (onStart) - Nastavak (onResume).
91. U terminal prozoru otkucati: telnet localhost 5554 2. Kada se pojavi odgovor od Android konzole, otkucati: gsm call 123456 3. Na ekranu emulatora će se pojaviti notifikacija poziva, koja će djelimično prekriti prozor tekuće aktivnosti. Ako se izabere odbijanje poziva (Dismiss) notifikacija će nestati i neće se pojaviti pop-up poruke. 4. U terminal prozoru ponovo otkucati: gsm call 123456 5. Ako se poziv prihvati (Answer), pojaviće se poruke Pauza (onPause) – Stop (onStop) i aktivnost phone aplikacije će potpuno prekriti tekuću aktivnost. 6. Kada se okonča poziv, aktivnost phone aplikacije će nestati i na ekranu se ponovo pojavljuje prethodna aktivnost sa porukama Restartovanje (onRestart) - Startovanje (onStart) - Nastavak (onResume).
10
11Napomena: Ako se koristi neki eksterni program za Telnet, treba ga podesiti tako što će se za "Host Name" staviti "localhost", za "Port" staviti "5554" i za protokol izabrati "Telnet". Kod nekih sistema treba izabrati "raw" protokol umjesto "Telnet".
12
13Dodatak – super keyword
14Super je ključna riječ u Javi.
15Koristi se: • Unutar definicije metode izvedene klase, da bi se pozvala metoda definisana u baznoj (roditeljskoj) klasi (super klasi). Ne mogu se pozivati privatne (private) metode bazne klase, već samo javne (public) i zaštićene (protected) metode. • U okviru konstruktora izvedene klase da pozove konstruktor bazne klase. Uvijek je potrebno pozivati odgovarajući konstruktor bazne klase u konstruktorima izvedene klase. Poziv konstruktora bazne klase mora biti prva naredba u tijelu konstruktora izvedene klase. Ukoliko to nije slučaj, kompajler će sam ubaciti poziv podrazumijevanog konstrukotra bazne klase (bez parametara, što uzrokuje grešku).
16Simulacija dolaznog telefonskog poziva
17Da bi se izvršila simulacija dolaznog telefonskog poziva kod Android simulatora, potrebno je pokrenuti Telnet aplikaciju. Može se koristiti bilo koja aplikacija za Telnet (npr. Putty), ali i Android studio u svom okruženju ima podršku za Telnet-ovanje. Potrebno je u donjem dijelu radnog prostora Android studija otvoriti prozor za Terminal
181. Na početku treba otvoriti Layout editor: u prozoru Project otvoriti fajl app > res > layout > activity_main.xml. Layout editor (Slika 1) ima dva tab-a: Design i Text. U Design prozoru se korisnički interfejs kreira grafički, a u Text prozoru se opisuje tekstualno koristeći XML. U daljem radu će se koristiti Design prozor, pa njega treba izabrati. U ovom prozoru se nalaze dvije podloge, jedna bijele i jedna tamnije boje. Na bijeloj podlozi se prikazuje korisnički interfejs onako kako će izgledati na uređaju, a tamnija podloga je tzv. blueprint (prikazuju se okviri svakog elementa, bez obzira da li je element zaklonjen nekim drugim
19elementom). Pomoću dugmeta i pripadajućeg menija, može se izabrati koja podloga će biti prikazana u ovom prozoru. 2. Pritisnuti dugme i čekirati opciju Show All Constraints. 3. Opcija Autoconnect treba da bude isključena (dugme treba da izgleda ovako: ). 4. Kliknuti na dugme Default Margins i izabrati 16
205. Ukloniti postojeći TextView (sa tekstom „Hello World!“) tako što se selektuje i pritisne taster delete. 6. U panelu Palette kliknuti na Text da bi se prikazale tekst kontrole. 7. Prevući kontrolu Plain Text u dizajn editor i pozicionirati je pri vrhu prozora (layout-a). Ova kontrola (EditText widget) omogućava unos teksta. 8. Kada se selektuje kontrola (klikom na nju unutar dizajn editora) pojavljuju se kvadratni simboli na uglovima, preko kojih se može vršiti promjena veličine objekta. Takođe, pojavljuju se i kružni simboli koji služe kao veze preko kojih se uređuje međusobni položaj kontrola.
219. Povući kružni simbol na gornjoj stranici do vrha prozora i tu ga otpustiti. Kontrola će biti automatski postavljena na 16 dp od vrha prozora (koliko je postavljena podrazumijevana margina u koraku 4). 10. Ponoviti isto sa lijevom stranom kontrole prema lijevoj ivici prozora. Slika 2 prikazuje izgled prozora nakon podešavanja položaja tekst kontrole u odnosu na gornju i lijevu ivicu prozora.
2211. U panelu Palette kliknuti na Buttons da bi se prikazale kontrole za dugmad. 12. Prevući kontrolu Button u dizajn editor i pozicionirati je pri desnoj ivici prozora (layout-a). 13. Podesiti razmak između tekst kontrole i dugmeta: povući kružni simbol sa lijeve ivice dugmeta prema kružnom simbolu na desnoj ivici tekst kontrole. Razmak će se automatski podesiti na 16 dp (podrazumijevana margina). 14. Da bi se vodoravno poravnale ove dvije kontrole treba selektovati dugme (klikom na njega), pritisnuti desni taster miša i iz menija izabrati Show Baseline 15. Pojaviće se oznaka za poravnavanje unutar dugmeta. Povući ovu oznaku prema odgovarajućoj oznaci koja će se pojaviti unutar tekst kontrole i otpustiti dugme miša. Time je izvršeno i horizontalno poravnavanje
2316. Sada je potrebno kreirati natpise koji će se nalaziti na ovim kontrolama. U Project prozoru otvoriti fajl app > res > values > strings.xml. U ovom fajlu se navode svi stringovi koji se koriste u projektu kako bi se nalazili na jednom mjestu i time se lakše uređivali (mijenjali, prevodili na više jezika, ...). 17. Izabrati Open editor u gornjem desnom uglu prozora. Otvoriće se Translations Editor, pomoću kojega se unose i mijenjaju stringovi, a služi i za organizaciju prevoda tih stringova na više jezika. 18. Kliknuti na Add Key (simbol + u gornjem lijevom uglu prozora) da bi kreirali novi string koji će služiti kao "hint" za tekst kontrolu. Pojaviće se novi prozor (Add Key) pomoću kojega se unosi novi string (Slika 5).
2419. Unutar Add Key prozora unijeti sljedeće: • Key: "poruka" • Default Value: "unesite poruku" U Resource Folder ostaviti ponuđeni sadržaj. 20. Dodati još jedan string (na isti način kao u prethodnim koracima) sa vrijednostima: "dugme" (Key) i "Pošalji" (Default Value). 21. Vratiti se u dizajn editor (izabrati tab "activity_main.xml"). 22. Selektovati tekst kontrolu. U Attributes prozoru, sa desne strane radne površine, izabrati atribut "text", koji trenutno ima vrijednost "Name", i obrisati ovu vrijednost. 23. Izabrati atribut "hint" i kliknuti na simbol koji se nalazi desno od boksa za unos teksta (Pick a Resource). U prozoru koji se pojavi (Pick a Resource) selektovati (dvoklikom) polje poruka. 24. Selektovati dugme i izabrati atribut "text", koji trenutno ima vrijednost "Button". 25. Kliknuti na simbol koji se nalazi desno od boksa za unos teksta (Pick a Resource). U prozoru koji se pojavi (Pick a Resource) selektovati (dvoklikom) polje dugme. Slika 6 prikazuje trenutni izgled radnog ekrana u dizajn editoru.
25Ukoliko želimo da se korisnički interfejs prilagođava različitim veličinama ekrana uređaja na kojima će se program izvršavati, potrebno je obezbijediti da se kontrole rašire kako bi zauzele čitavu površinu koja preostane nakog rezervisanja prostora za margine. Da bi se ovo postiglo treba izvršiti sledeće korake. 26. Selektovati obje kontrole: selektovati jednu, držati dugme Shift i kliknuti na drugu. Desnim tasterom miša kliknuti na bilo koju od ove dvije kontrole i izabrati Chains → Create Horizontal Chain1. Između kontrola će se pojaviti simbol koji asocira na lanac i kontrole će se prilagoditi širini ekrana. 27. Selektovati dugme i podesiti desnu marginu na 16 dp (Slika 7).
2628. Selektovati tekst kontrolu. U Attributes prozoru, kliknuti dva puta (ne dvoklik, nego sa pauzom) na indikator širine objekta (unutar Constraints Widget-a), kako bi se podesio na vrijednost Match Constraints (Slika 8). Match constraints znači da će se objekat (u ovom slučaju tekst kontrola) raširiti da popuni prostor koji preostaje kada se odvoji prostor za ostale objekte (u ovom slučaju dugme) i predviđene margine.
27
28Pokrenuti program u emulatoru ili na Android uređaju, kako bi se provjerili rezultati rada
29Pokretanje druge aktivnosti
30Pritiskom na dugme POŠALJI unutar realizovanog korisničkog interfejsa ne dešava se ništa, jer nije napisan kôd koji treba izvršiti kada se pritisne dugme. Sada je potrebno dodati kôd koji će pokrenuti novu aktivnost za ispis poruke, kada se pritisne dugme POŠALJI. 1. Otvoriti fajl MainActivity.java: app > java > com.example.mojprviprojekat > MainActivity. 2. Unutar MainActivity klase definisati metodu posaljiPoruku:
31
32public void posaljiPoruku(View v) { }
33
34Napomena: ukoliko se pojavi greška (Android studio ne može razriješiti klasu View koja se koristi kao argument metode – ključna riječ View je označena crvenom bojom) treba postaviti kursor unutar riječi View i pritisnuti Alt + Enter. U meniju koji će se pojaviti izabrati Import class. 3. Otvoriti activity_main.xml fajl: app > res > layout > activity_main.xml. 4. Selektovati dugme klikom na objekat u editoru. 5. U prozoru Attributes pronaći atribut onClick i izabrati posaljiPoruku [MainActivity] iz padajuće liste. Sada će sistem prilikom svakog pritiska na dugme POŠALJI pozvati metodu posaljiPoruku.
35
36Napomena 2: da bi se neka metoda mogla koristiti za poziv preko atributa onClick, ta metoda mora da bude public void i da ima jedan parametar i to View tipa.
37
38Sada je potrebno napisati kôd za metodu posaljiPoruku kojim će se pročitati sadržaj tekst kontrole i taj sadržaj isporučiti drugoj aktivnosti. U tu svrhu će se koristiti objekat Intent. On omogućava povezivanje između odvojenih komponenti (kao što su dvije aktivnosti) za vrijeme izvršavanja. Radi se zapravo o asinhronim porukama koje omogućavaju komponentama aplikacija da traže funkcionalnost od drugih Android komponenti. Omogućavaju komunikaciju sa komponentama iz istih aplikacija, kao i sa komponentama koje sadrže druge aplikacije. Može se koristiti za razne namjene, ali će se ovdje iskoristiti za pokretanje nove aktivnosti.
39
406. Definisati metodu posaljiPoruku na sljedeći način:
41public static final String EXTRA_PORUKA = "com.example.mojprviprojekat.PORUKA";
42
43public void posaljiPoruku(View v) { Intent i = new Intent(this, PrikaziPoruku.class); EditText editTekst = (EditText) findViewById(R.id.editText); String poruka = editTekst.getText().toString(); i.putExtra(EXTRA_PORUKA, poruka); startActivity(i); } Napomena 3: ukoliko se opet pojave greške (Cannot resolve symbol) treba ih ponovo otkloniti pomoću kombinacije Alt + Enter. Ostaće samo upozorenje na PrikaziPoruku.class, ali to je očekivano jer ta klasa još nije definisana. Intent konstruktor ima dva parametra: tipa Context i tipa Class.
44Context je interfejs sa globalnim informacijama o okruženju aplikacije. Ovo je apstraktna klasa koja omogućava pristup resursima aplikacije i klasama, kao i operacije na nivou aplikacije (pokretanje aktivnosti, emitovanje i prihvatanje Intenta, ...). Klasa tipa Class reprezentuje klase i interfejse u Java aplikaciji. U gornjem primjeru ovaj parametar je zapravo aktivnost kojoj se isporučuje Intent. U string poruka smješta se sadržaj koji je preuzet iz tekst kontrole editText. Metoda putExtra() dodaje sadržaj stringa poruka u Intent. Za identifikaciju se koristi tzv. ključ, koji se navodi kao prvi parametar metode (u gornjem primjeru sadržaj stringa "EXTRA_PORUKA"). Drugi parametar je vrijednost koja se pridružuje ključu. Metoda startActivity() pokreće instancu aktivnosti PrikaziPoruku koja je specificirana u Intent-u. Sljedeći korak je da se kreira klasa PrikaziPoruku, tj. nova aktivnost. 7. U prozoru Project kliknuti desnim tasterom miša na app folder i izabrati New → Activity → Empty Activity. Pojaviće se prozor Configure Activity (Slika 1).
458. U polje Activity Name unijeti PrikaziPoruku i izabrati Finish.
46Android studio će automatski: • kreirati fajl PrikaziPoruku.java; • kreirati layout fajl activity_prikazi_poruku.xml; • dodati <activity> tag u fajl AndroidManifest.xml:
47<activity android:name=".PrikaziPoruku"></activity>
48
49 Ako bi u ovom trenutku startovali aplikaciju, nakon pritiska na dugme POŠALJI pokrenula bi se nova aktivnost (prozor u aplikaciji). Međutim, nova aktivnost bi bila prazna jer je tako definisano u layout fajlu aktivnosti koji je automatski kreiran. Sada treba u novu aktivnost implementirati TextView kontrolu koja će prikazivati poslatu poruku. 9. Otvoriti fajl app > res > layout > activity_prikazi_poruku.xml. 10. Kliknuti na dugme Enable Autoconnection to Parent koje se nalazi na toolbar-u ( ). Na taj način će Autoconnect biti uključen. Dugme sada treba da izgleda ovako: . 11. U panelu Palette izabrati Text, i prevući TextView kontrolu na ekran dizajna negdje blizu vrha i sredine ekrana. Pojaviće se vertikalna linija koja treba da je otprilike po sredini kontrole. Zahvaljujući Autoconnect opciji pojaviće se ograničenja (constraints) sa lijeve i desne strane da bi se kontrola postavila u centar po horizontali. 12. Kreirati i constraint od vrha kontrole do vrha ekrana
5013. Selektovati kontrolu i u Attributes prozoru raširiti atribut textAppearance. Kod atributa textSize izabrati željenu veličinu fonta (npr. 18), a kod atributa textColor boju po želji.
51
52
5314. U klasi PrikaziPoruku, u metodu onCreate() (fajl PrikaziPoruku.java) dodati kôd tako da izgleda ovako:
54public class PrikaziPoruku extends AppCompatActivity {
55
56 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_prikazi_poruku);
57
58 // Prihvati Intent koji je pokrenuo ovu aktivnost i izvući string Intent i2 = getIntent(); String poruka = i2.getStringExtra(MainActivity.EXTRA_PORUKA);
59
60 // Postaviti sadržaj stringa kao tekst kontrole TextView TextView tekst = (TextView)findViewById(R.id.textView); tekst.setText(poruka); } } Napomena 4: ukoliko se opet pojave greške (Cannot resolve symbol) treba ih ponovo otkloniti pomoću kombinacije Alt + Enter.
61Pokrenuti program u emulatoru ili na Android uređaju, kako bi se provjerili rezultati rada.
62
63DODATAK
64Svaki ekran u aplikaciji koji nije početni ekran, treba da ponudi navigaciju koja korisnika usmjerava na roditeljski ekran u hijerarhiji aplikacije. Da bi to učinili kod ekrana koji pripada drugoj aktivnosti u prethodnom primjeru (activity_prikazi_poruku), treba dodati dugme za navigaciju (vraćanje „nazad“) na traci u vrhu prozora.
65Prilikom dodavanja dugmeta za navigaciju treba navesti koja aktivnost je roditeljska, u fajlu AndroidManifest.xml. Otvoriti fajl app > manifests > AndroidManifest.xml, i zamijeniti sadržaj <activity> taga za aktivnost PrikaziPoruku sa sljedećim:
66<activity android:name=".PrikaziPoruku" android:parentActivityName=".MainActivity"> <!-- meta-data tag je potreban za API nivoa 15 i nize --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity" /> </activity>
67 Kreiranje korisničkog interfejsa na drugi način (dinamički)
68U ranijim primjerima je pokazano kako se widget-i postavljaju na radni ekran pomoću design editora, odnosno kreiranjem odgovarajućeg XML fajla. Međutim, widget-e je moguće postavljati i dinamički, tokom izvršavanja programa, iz java koda. Za demonstraciju ćemo poći od primjera sa konvertorom između milja i kilometara.
69
701. Otvoriti projekat „Konvertor milje kilometri“. (Ili napraviti novi projekat u koji treba iskopirati sadržaje fajlova MainActivity.java i activity_main.xml iz projekta „Konvertor milje kilometri“). 2. Obrisati donje dugme (button_kmUmilje). Brisanje se može obaviti ili u design editoru ili u xml fajlu. Takođe, u fajlu MainActivity.java obrisati liniju:
71 Button dugmeKonvKmUMilje = (Button) findViewById(R.id.button_kmUmilje); 3. Ovo dugme ćemo kreirati dinamički, iz java koda. Prvo je potrebno deklarisati odgovarajuću promjenljivu:
72 Button dugmeKonvKmUMilje;
734. Potom je potrebno napraviti novu instancu ovog objekta:
74 dugmeKonvKmUMilje = new Button(getApplicationContext());
755. Zatim ćemo podesiti boju teksta na dugmetu:
76 dugmeKonvKmUMilje.setTextColor(Color.BLACK);
776. i boju samog dugmeta:
78 dugmeKonvKmUMilje.setBackgroundColor(Color.parseColor("#ABCDEF"));
797. Tekst na dugmetu se zadaje na sledeći način:
80 dugmeKonvKmUMilje.setText("KOnvertuj km u milje");
818. Da tekst ne bi bio uz same ivice dugmeta, treba dodati malo prostora:
82 dugmeKonvKmUMilje.setPadding(25,0,25,0);
839. Na ovaj način je dugme kreirano, ali još nije vidljivo na ekranu. Potrebno je zadati njegovu poziciju i „dodati“ ga ostalim objektima. Da bi se definisala pozicija na ekranu, mora se prvo zadati ID objektu u okviru kojeg se pozicionira, što je u ovom slučaju ConstraintLayout. Dakle, treba u design editoru selektovati ConstraintLayout i dati mu naziv npr. ConstraintLayout_glavni (Slika 1). 10. Potom se vrši pozicioniranje dugmeta u okviru layout-a:
84 ConstraintLayout glavniEkran = (ConstraintLayout) findViewById(R.id.ConstraintLayout_glavni); // glavniEkran povezujemo sa ConstraintLayout-om ConstraintLayout.LayoutParams parametri = new ConstraintLayout.LayoutParams( ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT ); // zadajemo parametre za ConstraintLayout parametri.topToBottom = dugmeKonvMiljeUKm.getId(); // novo dugme treba da bude ispod starog – njegov vrh ispod dna starog parametri.topMargin = 150; // margina (razmak) između njih // da bi dugme bilo centrirano u okviru layout-a: parametri.startToStart = ConstraintLayout.LayoutParams.PARENT_ID; parametri.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID; // dodati dugme sa gore zadatim parametrima glavniEkran.addView(dugmeKonvKmUMilje, parametri);
85Konačan sadržaj fajla MainActivity.java:
86import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout;
87
88import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText;
89
90import java.text.DecimalFormat;
91
92public class MainActivity extends AppCompatActivity { Button dugmeKonvKmUMilje;
93
94 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button dugmeKonvMiljeUKm = (Button) findViewById(R.id.button_miljeUkm); dugmeKonvMiljeUKm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { EditText textBoxMilje = (EditText) findViewById(R.id.editText_Milje); EditText textBoxKm = (EditText) findViewById(R.id.editText_Km); double Milje = Double.valueOf(textBoxMilje.getText().toString()); double Km = Milje / 0.621371192; DecimalFormat formatiranaVrijednost = new DecimalFormat("##.##"); textBoxKm.setText(formatiranaVrijednost.format(Km)); } }); dugmeKonvKmUMilje = new Button(getApplicationContext()); dugmeKonvKmUMilje.setTextColor(Color.BLACK); dugmeKonvKmUMilje.setBackgroundColor(Color.parseColor("#ABCDEF")); dugmeKonvKmUMilje.setText("Konvertuj km u milje"); dugmeKonvKmUMilje.setPadding(25,0,25,0); ConstraintLayout glavniEkran = (ConstraintLayout) findViewById(R.id.ConstraintLayout_glavni); ConstraintLayout.LayoutParams parametri = new ConstraintLayout.LayoutParams( ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT ); parametri.topToBottom = dugmeKonvMiljeUKm.getId(); parametri.topMargin = 150; // parametri.leftToLeft = dugmeKonvMiljeUKm.getId();
95 parametri.startToStart = ConstraintLayout.LayoutParams.PARENT_ID; parametri.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID; glavniEkran.addView(dugmeKonvKmUMilje, parametri); dugmeKonvKmUMilje.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { EditText textBoxMilje = (EditText) findViewById(R.id.editText_Milje); EditText textBoxKm = (EditText) findViewById(R.id.editText_Km); double Km = Double.valueOf(textBoxKm.getText().toString()); double Milje = Km * 0.621371192; DecimalFormat formatiranaVrijednost = new DecimalFormat("##.##"); textBoxMilje.setText(formatiranaVrijednost.format(Milje));
96
97 Organizovanje view-a na ekranu koristeći različite layout-e
98Zadatak je da napravimo aplikaciju koja će imati relativno složen sadržaj ekrana sastavljen od većeg broja widget-a, koje treba na određeni način rasporediti. Gornja trećina ekrana treba da bude svjetlo zelene pozadine sa dva dugmeta: jedno malo dugme i drugo veće, koje treba da zauzme polovinu preostalog prostora (po širini) u tom dijelu ekrana. Ispod ovog bloka treba rasporediti 9 dugmadi koja označavaju strane svijeta i nalaze se iznad slike kompasa postavljene u pozadini. Izgled ekrana aplikacije treba da bude kao na slici (Slika 1). 1. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project (Slika 2) izabrati Empty Activity i kliknuti na Next
993. Unutar Configure your project prozora (Slika 3) unijeti sljedeće:
100• Name: "Kompas" • Package name: "com.example.kompas" • podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE
101Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga. 6. Otvoriti fajl activity_main.xml i to njegov tekstualni oblik (tab Text). Obrisati TextView sa tekstom „Hello World!“, koji je Android studio kreirao sa projektom. Umjesto androidx.constraintlayout.widget.ConstraintLayout unijeti LinearLayout. Na taj način je umjesto podrazumijevanog ConstraintLayout-a podešen LinearLayout. 7. Pošto želimo da ekran bude podijeljen u redove, potrebno je specificirati orijentaciju ovog LinearLayout-a: android:orientation="vertical"
102
1038. Definišimo da kompozicija sadržaja prvog reda na ekranu takođe bude LinearLayout i podesimo da njegova širina bude ista kao širina nadređenog layout-a (match_parent), a visina 0px. <LinearLayout android:layout_width="match_parent" android:layout_height="0px" </LinearLayout>
104
1059. Definišimo da kompozicija sadržaja drugog reda na ekranu bude RelativeLayout i podesimo da njegova širina bude ista kao širina nadređenog layout-a (match_parent), a visina 0px. <RelativeLayout android:layout_width="match_parent" android:layout_height="0px"> </RelativeLayout>
106
10710. Pošto želimo da ova dva reda na ekranu zauzimaju prostor u odnosu 30%:70%, moramo specificirati da nadređeni layout zauzima 100% android:weightSum="100"
108
10911. da LinearLayout zauzima 30% android:layout_weight="30"
110
11112. a da RelativeLayout zauzima 70% android:layout_weight="70"
112
11313. Ako se pređe u dizajn editor, na prvi pogled se neće vidjeti efekat, ali ako se prevuče kursor preko ekrana pojaviće se vidljiva oznaka koliko koji red prostora zauzima. Da bi lakše razlikovali površine koje zauzimaju ova dva layout-a, za gornji ćemo definisati boju pozadine: android:background="@android:color/holo_green_light">
114
11514. U donji layout ćemo postaviti pozadinsku sliku. U tu svrhu ćemo iskoristiti sliku „kompas.jpg“. Ovu sliku treba prebaciti u clipboard (selektovati je na disku i izabrati copy) pa je iskopirati u res/drawable folder u Android studiju (Slika 5). Naime, slike koje se koriste u aplikaciji treba da budu u ovom folderu. Potom se slika referencira kod donjeg layout-a u dizajn editoru: android:background="@drawable/kompas"
11615. U gornji layout ćemo postaviti dva dugmeta, prevlačenjem sa palete. Prvo dugme želimo da zauzme samo onoliko prostora koliko je potrebno da stane njegov natpis. Daćemo mu ime (ID) „button_malo“, za tekst postaviti „malo“, a za širinu i visinu ostaviti „wrap_content“. Obrisaćemo atribut layout_weight. 16. Drugom dugmetu ćemo dati ID „button_veliko“, za tekst postaviti „VELIKO“ i obrisati atribut layout_weight. Želimo da ovo dugme po visini zauzme čitav gornji layout, pa ćemo postaviti da layout_height ima vrijednost „match_parent“. Po širini će zauzeti onoliko koliko je potrebno za ispis teksta jer je širina podešena na „wrap_content“. Ako želimo da drugo dugme zauzme npr. polovinu preostalog prostora, moramo prvo definisati ukupnu „težinu“ layout-a (uzmimo npr. da je ta težina 10): android:weightSum="10"
117
11817. a onda i „težinu“ dugmeta na pšolovinu gornje vrijednosti, pri čemu njegovu širinu treba postaviti na 0dp: android:layout_width="0dp" android:layout_weight="5"
119
120
12118. U ovom trenutku sadržaj fajla activity_main.xml izgleda ovako: <?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:weightSum="100" tools:context=".MainActivity">
122
123 <LinearLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="30" android:weightSum="10" android:background="@android:color/holo_green_light">
124 android:layout_height="wrap_content" android:text="malo" />
125
126 <Button android:id="@+id/button_veliko" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="5" android:text="VELIKO" /> </LinearLayout>
127
128 <RelativeLayout android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="70" android:background="@drawable/kompas"> </RelativeLayout>
129
130</LinearLayout>
131
13219. Sada ćemo rasporediti dugmad preko kompasa koji se nalazi u pozadini. Postavimo prvo dugme „sjever“ koje treba da bude centrirano po širini i sa malom marginom koja ga odvaja od vrha slike. Dajmo mu ID „button_sjever“, za tekst postaviti „SJEVER“, atribut layout_alignParentTop postaviti na true, atribut layout_centerHorizontal postaviti na true i atribut layout_marginTop postaviti na, recimo, 30dp. Da bi bilo uočljivije u odnosu na sliku, možemo mu promijeniti i atribut background birajući neku tamniju nijansu (npr. @android:color/darker_gray ili iz menija „Add new resource“>“New color Value“ izabrati boju po želji). 20. Postavimo dugme „jug“ koje treba da bude centrirano po širini i sa malom marginom koja ga odvaja od donjeg ruba slike. Dajmo mu ID „button_jug“, za tekst postaviti „JUG“, atribut layout_alignParentBottom postaviti na true, atribut layout_centerHorizontal postaviti na true, atribut layout_marginBottom postaviti na, recimo, 30dp i atribut background na @android:color/darker_gray. 21. Postavimo dugme „istok“ koje treba da bude centrirano po visini i sa malom marginom koja ga odvaja od desnog ruba slike. Dajmo mu ID „button_istok“, za tekst postaviti „ISTOK“, atribut layout_alignParentRight postaviti na true, atribut layout_centerVertical postaviti na true, atribut layout_marginRight postaviti na, recimo, 5dp i atribut background na @android:color/darker_gray. 22. Postavimo dugme „zapad“ koje treba da bude centrirano po visini i sa malom marginom koja ga odvaja od lijevog ruba slike. Dajmo mu ID „button_zapad“, za tekst postaviti „ZAPAD“, atribut layout_alignParentLeftpostaviti na true, atribut layout_centerVertical postaviti na true, atribut layout_marginLeft postaviti na, recimo, 5dp i atribut background na @android:color/darker_gray. 23. Postavimo dugme „centar“ koje treba da bude centrirano i po visini i po širini. Možemo ga kreirati u tekstualnom modu dizajn editora tako što ćemo iskopirati neko dugme i promijeniti parametre: <Button android:id="@+id/button_centar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@android:color/darker_gray" android:text="CENTAR" />
133„JugoZapad“. Dugme „SjeveroIstok“ će imati ID „button_SI“, natpis „SI“, i biće postavljeno ispod dugmeta „button_sjever“, iznad dugmeta „button_istok“, desno od dugmeta „button_sjever“ i lijevo od dugmeta „button_istok“: <Button android:id="@+id/button_SI" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/button_istok" android:layout_below="@id/button_sjever" android:layout_toRightOf="@id/button_sjever" android:layout_toLeftOf="@id/button_istok" android:background="@android:color/darker_gray" android:text="SI" /> 25. Dugme „SjeveroZapad“: <Button android:id="@+id/button_SZ" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/button_zapad" android:layout_below="@id/button_sjever" android:layout_toRightOf="@id/button_zapad" android:layout_toLeftOf="@id/button_sjever" android:background="@android:color/darker_gray" android:text="SZ" />
134
13526. Dugme „JugoIstok“: <Button android:id="@+id/button_JI" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/button_jug" android:layout_below="@id/button_istok" android:layout_toRightOf="@id/button_centar" android:layout_toLeftOf="@id/button_istok" android:background="@android:color/darker_gray" android:text="JI" />
136
13727. Dugme „JugoZapad“: <Button android:id="@+id/button_JZ" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/button_jug" android:layout_below="@id/button_zapad" android:layout_toRightOf="@id/button_zapad" android:layout_toLeftOf="@id/button_centar" android:background="@android:color/darker_gray" android:text="JZ" />
138
13928. Provjeriti izgled aplikacije na emulatoru
140Reprodukcija audio fajlova
141Zadatak je da napravimo aplikaciju koja će reprodukovati audio fajl. Postoje dva dugmeta: „Reprodukcija“ i „Pauza“, i „prekidač“ preko koga se bira da li će se fajl reprodukovati samo jednom ili će se reprodukcija neprekidno iznova ponavljati.
142Ako je prekidač postavljen tako da je ponavljanje isključeno, pritiskom na dugme „Reprodukcija“ započinje se reprodukcija audio fajla, a pritiskom na dugme „Pauza“ reprodukcija se zaustavlja. Ponovnim pritiskom dugmeta „Reprodukcija“ nastavlja se reprodukcija sa mjesta na kom je zaustavljena i tako do kraja fajla. Kada se stigne do kraja audio fajla, reprodukcija se zaustavlja. Da bi se reprodukcija nastavila potrebno je ponovo pritisnuti dugme „Reprodukcija“.
143Ako je prekidač postavljen tako da je ponavljanje uključeno, kada se stigne do kraja audio fajla reprodukcija počinje od početka, bez potrebe da se pritisne dugme „Reprodukcija“.
144Izgled ekrana aplikacije treba da bude kao na slici (Slika 1).
145
146Slika 1 1. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project (Slika 2) izabrati Empty Activity i kliknuti na Next.
147
148 3. Unutar Configure your project prozora (Slika 3) unijeti sljedeće: • Name: "Audio" • Package name: "com.example.audio" • podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE (Slika 4).
149 Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga. 6. Otvoriti fajl activity_main.xml i to dizajn editor (Design). Obrisati TextView sa tekstom „Hello World!“, koji je Android studio kreirao sa projektom. Potom prevući na ekran aplikacije prvo dugme (Button) koje će služiti za započinjanje reprodukcije. Neka natpis na dugmetu (atribut text) bude „Reprodukcija“, a njegov ID neka bude button_reprodukcija. 7. Pridružiti akciju ovom dugmetu tako što se definiše metoda koja će se izvršiti kada se pritisne dugme: atributu onClick pridružiti ime metode (npr. „pocniReprodukciju“). 8. Zatim prevući na ekran aplikacije drugo dugme (Button) koje će služiti za pauziranje reprodukcije. Neka natpis na dugmetu (atribut text) bude „Pauza“, a njegov ID neka bude button_pauza. 9. Pridružiti akciju ovom dugmetu tako što se definiše metoda koja će se izvršiti kada se pritisne dugme: atributu onClick pridružiti ime metode (npr. „pauzirajReprodukciju“). 10. Sada otvoriti fajl MainActivity.java i definisati ova dva metoda (moraju biti public void i moraju imati View argument):
150public void pocniReprodukciju(View v){ } public void pauzirajReprodukciju(View v) { } 11. Audio fajl koji želimo reprodukovati treba dodati među resurse aplikacije. Treba napraviti novi folder u folderu res, pa je postupak sledeći: kliknuti desnim tasterom na app (u Project prozoru) > New > Android Resource Directory. U dobijenom prozoru izabrati raw (Slika 5).
151
152
153Slika 5 12. Kreiran je novi folder app>res>raw u koji treba iskopirati audio fajl (copy-paste) audio_file.mp3. Sada je ovaj resurs inkorporiran u aplikaciju i može se iskoristiti korišćenjem MediaPlayer klase iz Android API-a. 13. Kreirati novi objekat MediaPlayer klase sa imenom npr. dzuboks:
154
155
156MediaPlayer dzuboks;
157
15814. U onCreate metodi treba inicijalizovati ovaj objekat tako što će mu se pridružiti audio fajl iz res/raw foldera (navodi se ime fajla bez ekstenzije):
159
160dzuboks = MediaPlayer.create(this,R.raw.audio_file);
161
16215. Nakon ovoga, započinjanje reprodukcije se vrši pozivom metode start() objekta dzuboks. Pauziranje reprodukcije se vrši pozivom metode pause() istog objekta:
163
164public void pocniReprodukciju(View v){ dzuboks.start(); } public void pauzirajReprodukciju(View v) { dzuboks.pause(); } 16. Pauziranje reprodukcije ima smisla samo ako je reprodukcija u toku. Zato ćemo pozivati metod pause() samo kada je reprodukcija u toku:
165public void pauzirajReprodukciju(View v) { if(dzuboks.isPlaying()) // reprodukcija u toku dzuboks.pause(); } 17. Sada treba dodati prekidač preko koga će korisnik odlučiti da li da reprodukuje audio fajl samo jednom ili da se reprodukcija automatski nastavlja od početka kada se dođe do kraja fajla. U dizajn editoru prevući widget switch na površinu ekrana i pozicionirati ga po želji. Dati mu ID (npr. switch_ponavljanje) i unijeti sadržaj atributa text koji će biti ispisan pored prekidača (npr. Ponavljanje). 18. U java kodu treba kreirati Switch objekat (npr. prekidacPonavljanja) i povezati ga sa upravo postavljenim prekidačem (u okviru onCreate() metode):
166
167 Switch prekidacPonavljanja = (Switch)findViewById(R.id.switch_ponavljanje);
168
16919. Kada postoji referenca prema prekidaču možemo pridružiti listener koji će pratiti promjenu stanja prekidača i omogućiti da se prilikom promjene obavi neka akcija (setOnCheckedChangeListener). Kreira se novi anonimni objekat OnCheckedChangeListener i implementira metoda onCheckedChanged() (automatski prilikom kreiranja objekta):
170
171prekidacPonavljanja.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { } });
172
17320. Sada treba definisati metodu onCheckedChanged() tako da se utvrdi položaj prekidača (preko argumenta b – boolean promjenljiva koja ima vrijednost true ako je prekidač u položaju ON, odnosno false ako je prekidač u položaju OFF) i na osnovu toga konfiguriše način reprodukcije:
174 dzuboks.setLooping(b);
175
17621. Konačan izgled fajla MainActivity.java:
177
178package com.example.audio;
179
180import androidx.appcompat.app.AppCompatActivity;
181
182import android.media.MediaPlayer; import android.os.Bundle; import android.view.View; import android.widget.CompoundButton; import android.widget.Switch;
183
184public class MainActivity extends AppCompatActivity { MediaPlayer dzuboks;
185
186 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dzuboks = MediaPlayer.create(this,R.raw.audio_file); Switch prekidacPonavljanja = (Switch)findViewById(R.id.switch_ponavljanje); prekidacPonavljanja.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { dzuboks.setLooping(b); } }); } public void pocniReprodukciju(View v){ dzuboks.start(); } public void pauzirajReprodukciju(View v) { if(dzuboks.isPlaying()) dzuboks.pause(); } }
187
18822. Provjeriti rad aplikacije na emulatoru.
189Snimanje podataka na Android uređaju
190Zadatak je da napravimo aplikaciju koja će moći da zapamti konfiguraciju koja je zadata prilikom poslednjeg podešavanja tako što će podatke o konfiguraciji snimiti na samom uređaju i kasnije ih preuzimati. Izborom jednog od radio dugmadi podešava se odgovarajuća boja pozadine ekrana i istovremeno se informacija o tome koja je boja izabrana čuva u fajlu na Android uređaju. Pritiskom na dugme na ekranu, očitava se fajl sa informacijom o boji i pozadina ekrana se podešava na tu boju. Izgled ekrana aplikacije treba da bude kao na slici (Slika 1).
191
192Slika 1 1. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project (Slika 2) izabrati Empty Activity i kliknuti na Next.
1933. Unutar Configure your project prozora (Slika 3) unijeti sljedeće: • Name: "Konfiguracija" • Package name: "com.example.konfiguracija" • podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE (Slika 4).
194 Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga. 6. Otvoriti fajl activity_main.xml i to dizajn editor (Design). Promijeniti tekst u widget-u TextView koji je Android studio kreirao sa projektom: umjesto „Hello World!“ upisati „Izabrati boju pozadine:“. Pozicionirati ga pri vrhu ekrana i izabrati da slova budu malo veća (atribut textAppearance postaviti na @style/TextAppearance.AppCompat.Large). 7. Ispod TextView widget-a postaviti widget RadioGroup iz sekcije Buttons, dati mu ID (npr. radioGrupa) i podesiti dimenzije. 8. Unutar RadioGroup widget-a postaviti (prevlačenjem iz palete) tri radio dugmeta (RadioButton), dati im imena i unijeti tekst koji će stajati pored njih. Neka imena budu radioButton_plava, radioButton_zuta i radioButton_zelena, a tekst „Plava“, „Žuta“ i „Zelena“, respektivno. 9. Potom prevući na ekran aplikacije dugme (Button) koje će služiti za učitavanje konfiguracije (zadate boje pozadine). Neka natpis na dugmetu (atribut text) bude „Učitaj konfiguraciju“, a njegov ID neka bude button_ucitaj. 10. Pošto ćemo mijenjati boju pozadine ekrana, moramo zadati ID i layout-u kako bi ga mogli referencirati. Neka ovaj ID bude „ekran“. 11. U java kodu sada treba implementirati željenu interaktivnost. Prvo kreirati objekat (neka se i on zove ekran) koji će referencirati layout (mora biti final pošto će mu se pristupati iz druge klase):
195
196 final ConstraintLayout ekran = (ConstraintLayout)findViewById(R.id.ekran);
197
19812. Potom kreirati objekat (neka se zove radioGrupaBoje) koji će referencirati radio grupu RadioGrupa:
199
200 RadioGroup radioGrupaBoje = (RadioGroup)findViewById(R.id.radioGrupa);
201
20213. Sada treba ovom objektu pridružiti listener (sa setOnCheckedChangeListener), kako bi se mogla obaviti neka radnja kada se klikne na radio dugme, i dodati novi RadioGroup.OnCheckedChangeListener:
203
204radioGrupaBoje.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) {
205
206 } }); } 14. Kada se klikne na pojedino radio dugme u okviru radio grupe, i promjenljivoj i se nalazi ID selektovanog radio dugmeta. Zavisno od vrijednosti ovog parametra treba podesiti poju pozadine ekrana. Ako vrijednost promjenljive i odgovara widget-u radioButton_plava, boju pozadine treba postaviti na plavu boju:
207
208if(i == R.id.radioButton_plava) ekran.setBackgroundColor(Color.BLUE);
209 15. Ako vrijednost promjenljive i odgovara widget-u radioButton_zuta, boju pozadine treba postaviti na žutu boju, a ako odgovara widget-u radioButton_zelena, boju pozadine treba postaviti na zelenu boju:
210
211public void onCheckedChanged(RadioGroup radioGroup, int i) { if(i == R.id.radioButton_plava) ekran.setBackgroundColor(Color.BLUE); else if(i == R.id.radioButton_zuta) ekran.setBackgroundColor(Color.YELLOW); else if(i == R.id.radioButton_zelena) ekran.setBackgroundColor(Color.GREEN); }
212
21316. Ako pokrenemo aplikaciju vidjećemo da promjena boje pozadine funkcioniše, ali da se zatvaranjem aplikacije i ponovnim pokretanjem gubi prethodno podešavanje. Potrebno je negdje sačuvati informaciju o izabranoj boji. To se može uraditi na više načina. Ovdje ćemo koristiti tzv. preferences gdje se informacije čuvaju u parovima „ključvrijednost“ u xml fajlu. Objekat koji omogućava manipulaciju sa ovim podacima je tipa SharedPreferences. Zato je potrebno kreirati objekat ovog tipa (neka se zove konfiguracija) i pomoću metode getSharedPreferences() zadati ime fajla (npr. „BOJE“ - ako već ne postoji Android će ga kreirati prilikom prvog poziva) i mod za pristup. Ako želimo da ovim podacima pristupa samo naša aplikacija, izabraćemo Context.MODE_PRIVATE:
214
215final SharedPreferences konfiguracija = getSharedPreferences("BOJA", Context.MODE_PRIVATE);
216
21717. Potom je potrebno kreirati tzv. editor za ovaj fajl (neka se zove editor), koristeći edit() metodu:
218
219final SharedPreferences.Editor editor = konfiguracija.edit();
220
22118. Sada je moguće izabranu boju upisivati u definisani fajl. Za pamćenje izabrane boje uvešćemo cjelobrojnu promjenljivu sifraBoje u metodi onCheckedChanged() i inicijalizovati je na nulu:
222
223int sifraBoje = 0;
224
22519. Pri svakoj promjeni boje pozadine, u ovu promjenljivu ćemo upisati kod za tu boju:
226
227public void onCheckedChanged(RadioGroup radioGroup, int i) { int sifraBoje = 0; if(i == R.id.radioButton_plava) { ekran.setBackgroundColor(Color.BLUE); sifraBoje = Color.BLUE; } else if(i == R.id.radioButton_zuta) { ekran.setBackgroundColor(Color.YELLOW); sifraBoje = Color.YELLOW; } else if(i == R.id.radioButton_zelena) { ekran.setBackgroundColor(Color.GREEN); sifraBoje = Color.GREEN; } }
228Napomena: ovaj kod je moguće optimalnije napisati, ali to sada nije predmet našeg interesovanja!
229
23020. Konačno, šifru boje koja se nalazi u promjenljivoj sifraBoje treba upisati u fajl BOJA.xml. To se može uraditi pomoću put metode editora (u ovom slučaju putInt() pošto je int promjenljiva). Metoda ima dva argumenta: naziv ključa (npr. Color) i vrijednost koju treba upisati:
231
232editor.putInt("Color",sifraBoje);
233
23421. Međutim, podatak neće biti snimljen u fajl dok se ne izvrši metoda commit()!!!
235
236editor.commit();
237
23822. Ostalo je da prilikom pritiska na dugme button_ucitaj (dugme sa natpisom „Učitaj konfiguraciju“) pročitamo sadržaj fajla BOJA.xml (ako on postoji) i da podesimo boju pozadine koju tamo pročitamo. Kreirati objekat koji će referencirati ovo dugme (neka se zove dugme):
239
240Button dugme = (Button)findViewById(R.id.button_ucitaj);
241
24223. Sada dugmetu pridružiti listener u okviru čije onClick() metode će se očitati vrijednost iz fajla i podesiti boja pozadine:
243
244dugme.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(konfiguracija.contains("Color")) // postoji ključ "Color" ekran.setBackgroundColor(konfiguracija.getInt("Color",0)); // drugi argument je default vrijednost } }); 24. Konačan izgled fajla MainActivity.java:
245
246package com.example.konfiguracija;
247
248import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout;
249
250import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.RadioGroup;
251
252public class MainActivity extends AppCompatActivity {
253
254 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
255
256 Button dugme = (Button)findViewById(R.id.button_ucitaj);
257
258 final SharedPreferences konfiguracija = getSharedPreferences("BOJA", Context.MODE_PRIVATE); final SharedPreferences.Editor editor = konfiguracija.edit();
259 final ConstraintLayout ekran = (ConstraintLayout)findViewById(R.id.ekran);
260
261 RadioGroup radioGrupaBoje = (RadioGroup)findViewById(R.id.radioGrupa); radioGrupaBoje.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { int sifraBoje = 0; if(i == R.id.radioButton_plava) { ekran.setBackgroundColor(Color.BLUE); sifraBoje = Color.BLUE; } else if(i == R.id.radioButton_zuta) { ekran.setBackgroundColor(Color.YELLOW); sifraBoje = Color.YELLOW; } else if(i == R.id.radioButton_zelena) { ekran.setBackgroundColor(Color.GREEN); sifraBoje = Color.GREEN; } editor.putInt("Color",sifraBoje); editor.commit(); } }); dugme.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(konfiguracija.contains("Color")) // postoji ključ "Color" ekran.setBackgroundColor(konfiguracija.getInt("Color",0)); } }); } } 25. Provjeriti rad aplikacije na emulatoru.
262Sakrivanje i prikazivanje widget-a na ekranu
263Zadatak je da napravimo aplikaciju koja će moći da sakrije odnosno ponovo prikaže neki od widgeta na ekranu. Kao primjer, View koji će služiti da se sakrije, odnosno ponovo prikaže, će biti TextView koji Android studio po default-u postavi na ekran. Pomoću dugmeta sa natpisom „Sakrij“ će se vršiti sakrivanje View-a, a pomoću dugmeta sa natpisom „Prikaži“ će se vršiti ponovno prikazivanje.
264Izgled ekrana aplikacije treba da bude kao na slici (Slika 1).
265
266Slika 1 1. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project (Slika 2) izabrati Empty Activity i kliknuti na Next.
267
268
269Slika 2 3. Unutar Configure your project prozora (Slika 3) unijeti sljedeće: • Name: "Sakrivanje" • Package name: "com.example.sakrivanje"
270• podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE (Slika 4).
271
272Slika 3
273
274Slika 4
275Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga.
2766. Otvoriti fajl activity_main.xml i to dizajn editor (Design). Selektovati widget TextView i povećati slova izborom atributa textAppearance i izborom opcije Large iz padajuće liste. Da bi bio uočljiviji, podesiti i boju pozadine: atribut backgdound postaviti na npr. holo_orange_light. Promijeniti mu ID u textView_tekst. 7. Prevući u gornjem dijelu ekrana aplikacije dugme (Button) koje će služiti za sakrivanje widget-a. Neka natpis na dugmetu (atribut text) bude „Sakrij“, a njegov ID neka bude button_sakrij. 8. Prevući pored njega dugme (Button) koje će služiti za prikazivanje widget-a. Neka natpis na dugmetu (atribut text) bude „Prikaži“, a njegov ID neka bude button_prikazi. Ne zaboraviti da se podeste constraint parametri za oba dugmeta kako bi se zaista našli na željenim pozicijama. 9. Pritiskom na dugme treba da se izvrši određena akcija. Vrsta akcije (sakrij ili prikaži View) zavisi od toga koje je dugme pritisnuto. Za svako dugme može da se veže posebna metoda ili da mu se pridruži odgovarajući listener kojima će se obaviti željena akcija. Međutim, u ovom primjeru ćemo definisati samo jednu metodu koja će obavljati akciju zavisno od toga koje je dugme pritisnuto. Neka se ta metoda zove akcija(). U fajlu MainActivity.java u okviru MainActivity klase definisati ovu metodu:
277
278public void akcija(View v) { // argument je View koji je pozvao metodu }
279
28010. Deklarisati i objekte za dva dugmeta i natpis koji se nalaze na ekranu:
281
282Button button_Sakrij, button_Prikazi; TextView textView_Tekst;
283
28411. Uspostaviti reference:
285
286button_Sakrij = (Button)findViewById(R.id.button_sakrij); button_Prikazi = (Button)findViewById(R.id.button_prikazi); textView_Tekst = (TextView)findViewById(R.id.textView_tekst);
287
28812. Unutar metode akcija() izvršiti ispitivanje koji je View uzrokovao poziv (proslijeđen je kao argument) i sprovesti odgovarajuću akciju nad objektom TextView. Ispitivanje se vrši pozivanjem metode equals(). Podešavanje vidljivosti se vrši metodom setVisibility(). Kada želimo da objekat učinimo nevidljivim ovoj metodi se prosleđuje View.INVISIBLE. U suprotnom se prosleđuje View.VISIBLE.
289
290public void akcija(View v) { if(v.equals(button_Sakrij)) textView_Tekst.setVisibility(View.INVISIBLE); // učini nevidljivim if(v.equals(button_Prikazi)) textView_Tekst.setVisibility(View.VISIBLE); // učini vidljivim }
291
29213. Konačan izgled fajla MainActivity.java:
293
294package com.example.sakrivanje;
295
296import androidx.appcompat.app.AppCompatActivity;
297
298import android.os.Bundle; import android.view.View;
299import android.widget.Button; import android.widget.TextView;
300
301public class MainActivity extends AppCompatActivity { Button button_Sakrij, button_Prikazi; TextView textView_Tekst;
302
303 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button_Sakrij = (Button)findViewById(R.id.button_sakrij); button_Prikazi = (Button)findViewById(R.id.button_prikazi); textView_Tekst = (TextView)findViewById(R.id.textView_tekst); }
304
305 public void akcija(View v) { if(v.equals(button_Sakrij)) textView_Tekst.setVisibility(View.INVISIBLE); // učini nevidljivim if(v.equals(button_Prikazi)) textView_Tekst.setVisibility(View.VISIBLE); // učini vidljivim } }
306
30714. Provjeriti rad aplikacije na emulatoru.
308
309Moguće je ispitati da li je neki View trenutno vidljiv ili ne, koristeći metodu getVisibility(). Koristeći ovu metodu, moguće je sakrivati/prikazivati neki View koristeći samo jedno dugme: ako je View sakriven, pritiskom na dugme će biti otkriven, a ako je otkriven, pritiskom na dugme će biti sakriven.
310
31115. Obrisati jedno od dugmadi na ekranu, a drugome promijeniti natpis u „Sakrij/Prikaži“ i postaviti ID da bude button_dugme. Ažurirati deklaraciju objekta i referencu za ovo dugme. 16. Metodu akcija() ažurirati tako da se provjerava da li je textView_Tekst vidljiv ili ne i na osnovu te informacije podesiti njegovu vidljivost:
312
313public void akcija(View v) { if(textView_Tekst.getVisibility() == View.VISIBLE) textView_Tekst.setVisibility(View.INVISIBLE); // učini nevidljivim else textView_Tekst.setVisibility(View.VISIBLE); // učini vidljivim }
314
31517. Provjeriti rad aplikacije na emulatoru.
3161. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project izabrati Empty Activity i kliknuti na Next. 3. Unutar Configure your project prozora unijeti sljedeće: • Name: "Web stranice" • Package name: "com.example.webstranice" • podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE.
317Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga. 6. Otvoriti dizajn editor i ukloniti TextView sa tekstom „Hello World!“ koji je generisao Android studio. 7. U tekstualnom modu unijeti NumberPicker i podesiti njegovu poziciju na ekranu:
318
319<NumberPicker android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> </NumberPicker>
320
3218. Ispod njega postaviti dugme sa natpisom „OK“, čiji je ID „button_ok“, i podesiti constraint-e. Pritiskom na dugme (onClick atribut) poziva se funkcija navigacija():
322<Button android:id="@+id/button_ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginLeft="16dp" android:onClick="navigacija" android:text="@android:string/ok" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/numberPicker" />
323
3249. Ispod dugmeta pozicionirati WebView (u paleti se nalazi u grupi Widgets), dati mu ime webView i takođe podesiti constraint-e:
325
326 <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button_ok" />
327
32810. U java kodu (MainActivita.java) deklarisati NumberPicker objekat (neka se zove izbor) i uspostaviti referencu prema widget-u na ekranu:
329
330public class MainActivity extends AppCompatActivity { NumberPicker izbor;
331
332 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); izbor = (NumberPicker)findViewById(R.id.numberPicker); } } 11. Sada treba definisati niz stringova koji će biti prikazani kao mogući izbori u NumberPicker-u. Neka se taj niz zove moguciIzbor i neka članovi tog niza budu „Android“, „Tablet“, „Android studio“ i „ETF“:
333
334String[] moguciIzbor = {"Android","Tablet","Android studio","ETF"};
335
33612. Ovaj string treba povezati sa NumberPicker-om:
337
338izbor.setDisplayedValues(moguciIzbor);
339
34013. Konačno, treba specificirati da NumberPicker nudi 4 opcije koje su indeksirane od 0 do 3:
341
342izbor.setMinValue(0); izbor.setMaxValue(moguciIzbor.length -1);
343
34414. Pogledati rezultat u emulatoru.
345
34615. Sada u java kodu treba definisati funkciju navigacija() koja će biti pozvana kada se pritisne dugme. Funkcija mora biti tipa public void i ima jedan argument tipa View koji pokazuje na dugme. Kada se dugme pritisne treba u promjenljivu (neka se zove izabrano) smjestiti korisnikov izbor u NumberPicker-u. U tu svrhu se može koristiti metoda getValue(), koja vraća indeks izabranog stringa:
347
348int izabrano = izbor.getValue();
349
35016. Na osnovu sadržaja promjenljive (tj. izabranog stringa) treba prikazati sadržaj odgovarajuće web stranice u WebView-u. Zato treba deklarisati WebView objekat (neka se zove webView) i u metodi onCreate() uspostaviti referencu prema odgovarajućem widget-u na ekranu.
351webView = (WebView)findViewById(R.id.webView);
352
35317. Od ove četiri opcije koje su ponuđene za izbor, prve dvije su linkovi na html fajlove koji se nalaze na samom uređaju, tj. predstavljaju lokalne resurse. Zato se oni moraju dodati u projekat. Potrebno je kreirati Assets folder: desni taster miša na app, pa izabrati New>Folder>Assets Folder>Finish (ostaviti podrazumijevane vrijednosti). U ovaj folder iskopirati (copy-paste) potrebne fajlove (android.htm i tablet.htm). 18. U java kodu treba učitati odgovarajući resurs u WebView zavisno od toga šta je korisnik izabrao u NumberPicker-u. Ako je vrijednost promjenljive izabrano jednaka 0, u WebView treba učitati fajl android.htm ("file:///android_asset/android.html"):
354
355if(izabrano == 0) webView.loadUrl("file:///android_asset/android.html");
356
35719. Za ostale vrijednosti promjenljive izabrano treba učitati odgovarajuće web stranice (kod web stranica koje treba preuzeti sa Interneta umjesto „file:///“ stavlja se „http://“):
358
359else if(izabrano == 1) webView.loadUrl("file:///android_asset/tablet.html"); else if(izabrano == 2) webView.loadUrl("http://en.wikipedia.org/wiki/Android_Studio"); else if(izabrano == 3) webView.loadUrl("http://www.etf.ucg.ac.me");
360
36120. Startovati aplikaciju u emulatoru i probati sa izborom opcija. Ukoliko se izabere neka od prve dvije opcije (android ili tablet) prikazaće se odgovarajuća html stranica u okviru naše aplikacije. Klikom na neki od linkova otvoriće se podrazumijevani web browser i u njemu sadržaj linkovane stranice. Međutim, ako se izabere neka od druge dvije opcije (sa Interneta) javiće se poruka o grešci i stranica neće biti učitana. Razlog je što naša aplikacija nema pravo pristupa Internetu. Ovo pravo (dozvola) se specificira u AndroidManifest-u. Odmah ispod definicije aplikacije se navodi:
362
363<uses-permission android:name="android.permission.INTERNET"/>
364
36521. a unutar application taga:
366
367android:usesCleartextTraffic="true"
368
36922. Fajl AndroidManifest.xml sada izgleda ovako:
370
371<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.webstranice">
372
373 <uses-permission android:name="android.permission.INTERNET"/>
374
375 <application android:usesCleartextTraffic="true" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" />
376
377 <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
37823. Ako ponovo pokrenemo aplikaciju vidjećemo da će se linkovi ka stranicama na Internetu (poslednje dvije opcije) otvoriti u novoj aktivnosti (kao i linkovi unutar fajlova iz prve dvije opcije).
379
380Napomena: ukoliko se u emulatoru i dalje javlja poruka da je došlo do greške koja onemogućava otvaranje web stranice, deinstalirati aplikaciju sa emulatora, pa ponovo pokrenuti instalaciju.
381
382Ako želimo da se web stranica prikaže unutar naše aplikacije (u WebView-u), prije poziva za učitavanje URL-a treba definisati web klijenta:
383
384webView.setWebViewClient(new WebViewClient());
385
38624. Konačan izgled java koda (MainActivity.java):
387
388import androidx.appcompat.app.AppCompatActivity;
389
390import android.os.Bundle; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.NumberPicker;
391
392public class MainActivity extends AppCompatActivity { NumberPicker izbor; WebView webView;
393
394 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
395
396 izbor = (NumberPicker)findViewById(R.id.numberPicker); String[] moguciIzbor = {"Android","Tablet","Android studio","ETF"}; izbor.setDisplayedValues(moguciIzbor); izbor.setMinValue(0); izbor.setMaxValue(moguciIzbor.length -1); webView = (WebView)findViewById(R.id.webView); webView.setWebViewClient(new WebViewClient()); } public void navigacija(View v) { int izabrano = izbor.getValue(); if(izabrano == 0) webView.loadUrl("file:///android_asset/android.html"); else if(izabrano == 1) webView.loadUrl("file:///android_asset/tablet.html"); else if(izabrano == 2) webView.loadUrl("http://en.wikipedia.org/wiki/Android_Studio"); else if(izabrano == 3) webView.loadUrl("http://www.etf.ucg.ac.me"); } }
397
39825. Konačan izgled fajla activity_main.xml:
399<?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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
400
401 <Button android:id="@+id/button_ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp"
402 android:layout_marginLeft="16dp" android:onClick="navigacija" android:text="@string/ok" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/numberPicker" />
403
404 <NumberPicker android:id="@+id/numberPicker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
405
406 <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button_ok" />
407
408</androidx.constraintlayout.widget.ConstraintLayout>
409 1. Na početnom ekranu (Welcome to Android Studio) izabrati Start a new Android Studio project. Ukoliko je već otvoren neki projekat, izabrati File → New → New Project. 2. U prozoru Choose your project izabrati Empty Activity i kliknuti na Next. 3. Unutar Configure your project prozora unijeti sljedeće: • Name: "Slanje poruke" • Package name: "com.example.slanjeporuke" • podesiti lokaciju gdje će projekat biti sačuvan • Language: "Java" • podesiti željeni API nivo. 4. Kliknuti na Finish. 5. Nakon nekog vremena otvoriće se Arduino studio IDE. Provjeriti da li je otvoren prozor Project i ako nije otvoriti ga (View → Tool Windows → Project). Takođe, provjeriti da li je iz padajućeg menija u vrhu Project prozora izabran Android i ako nije izabrati ga. 6. Otvoriti dizajn editor i ukloniti TextView sa tekstom „Hello World!“ koji je generisao Android studio. 7. Prevući Multiline Text widget sa palete (nalazi se u grupi Widgets) na ekran i pozicionirati ga prema želji, te mu podesiti constraint-e. Neka njegov ID bude editText_poruka. Staviti da je atribut hint – „Unesi poruku“. Ovaj tekst će biti prikazan u polju za unos sve dok korisnik ne uđe u to polje i otkuca prvi karakter. 8. Prevući dugme i pozicionirati ga ispod Multiline Text widget-a. Neka njegov ID bude button_posalji, a natpis „Pošalji“. Podesiti da se na onClick poziva metoda posaljiPoruku(). 9. Definisati ovu metodu u java kodu (fajl MainActivity.java):
410public void posaljiPoruku(View v){
411
412}
41310. U ovoj metodi treba da preuzmemo tekst koji je otkucan u tekst boksu i da ga predamo aplikaciji koja može da pošalje SMS. Kreirajmo promjenljivu poruka koja će sadržati tekst koji je korisnik unio:
414
415String poruka = ((EditText)findViewById(R.id.editText_poruka)).getText().toString();
416
41711. Da bi ovu poruku predali drugoj aplikaciji kreiramo Intent (neka se zove smsIntent). Želimo da pokrenemo aktivnost koja može poslati SMS, ali nećemo eksplicitno navesti koja je to aplikacija. Dakle, kreiraćemo implicitni Intent. Operativni sistem će utvrditi koje su se aplikacije deklarisale da mogu slati SMS-ove. Ako ih ima više, korisnik može biti upitan da izabere jednu od njih. U ovom slučaju, tražimo aplikaciju koja može da izvrši ACTION_SENDTO. Ovaj Intent zahtjeva da mu saopštimo i odredište, tj. kome šaljemo poruku. Zato kreiramo Uri objekat po imenu odrediste. Pošto mi šaljemo SMS sa jednog emulatora na drugi, koristićemo njihove oznake: jedan je 5554, a drugi 5556. Uzećemo da sa prvog šaljemo poruku na drugi (odredište je 5556). Format adrese je „smsto:broj_telefona“. Naravno, kod realnih uređaja koristio bi se stvarni broj telefona.
418Uri odrediste = Uri.parse("smsto:5556"); Intent smsIntent = new Intent(Intent.ACTION_SENDTO,odrediste);
419
42012. Drugoj aktivnosti treba proslijediti poruku, pa koristimo putExtra() metodu u kojoj je ključ „sms_body“:
421
422smsIntent.putExtra("sms_body",poruka);
423
42413. Funkcija posaljiPoruku () izgleda ovako:
425
426public void posaljiPoruku(View v) { String poruka = ((EditText)findViewById(R.id.editText_poruka)).getText().toString(); Uri odrediste = Uri.parse("smsto:5556"); Intent smsIntent = new Intent(Intent.ACTION_SENDTO,odrediste); smsIntent.putExtra("sms_body",poruka); startActivity(smsIntent); }
427
42814. Provjeriti rad aplikacije. Potrebno je kreirati i pokrenuti dva emulatora različitih uređaja!
429
43015. Konačan izgled java koda (MainActivity.java):
431
432package com.example.slanjeporuke;
433
434import androidx.appcompat.app.AppCompatActivity;
435
436import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.EditText;
437
438public class MainActivity extends AppCompatActivity {
439
440 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void posaljiPoruku(View v) { String poruka = ((EditText)findViewById(R.id.editText_poruka)).getText().toString(); Uri odrediste = Uri.parse("smsto:5556"); Intent smsIntent = new Intent(Intent.ACTION_SENDTO,odrediste); smsIntent.putExtra("sms_body",poruka); startActivity(smsIntent); } }
441
44216. Konačan izgled xml fajla activity_main.xml: <?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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
443
444 <EditText android:id="@+id/editText_poruka" android:layout_width="320dp" android:layout_height="230dp" android:layout_marginTop="60dp" android:ems="10" android:gravity="start|top" android:hint="@string/unesi_poruku" android:inputType="textMultiLine" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
445
446 <Button android:id="@+id/button_posalji" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="120dp" android:onClick="posaljiPoruku" android:text="Pošalji" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/editText_poruka" /> </androidx.constraintlayout.widget.ConstraintLayout>