U Android Studio se dizajniranje aplikacije može odraditi na nekoliko načina. Za sada ćemo prikazati onaj najteži, ali i najbolji za razumevanje. Kasnije ćemo videti kako se na mnogo lakši način može dizajnirati aplikacija.
Dizajniranje aplikacije se odvija zadavanjem instrukcija u određenom XML fajlu na jeziku koji je mnogo sličan jeziku HTML. Naša aplikacija potom pročita taj fajl i zna kako da generiše odgovarajuće vizuelne elemente. Na ovaj način je dizajn odvojen od programiranja aplikacije i lakše se vrše izmene, jer je ovaj pristup pregledniji.
Osnovna sintaksa jezika u XML fajlu je sledeća:
<naziv osobina_1 = "vrednost_1" ... osobina_n = "vrednost_n" />
Omogućeno je i da elementi sadrže jedni druge. To je posebno zgodno ako imamo neki layout u kojem raspoređujemo elemente po nekom pravilu (recimo jedne ispod drugih ili u pravougaonu mrežu). Tada bi sintaksa izgledala ovako:
<parent osobina_1 = "vrednost_1" ... osobina_n = "vrednost_n" > <child osobine.... /> </parent>
Izgled aplikacije je zapisan u fajlu activity_main.xml koji se nalazi na adresi app/src/main/res/layout. Za sada ćemo obrisati sav sadržaj fajla i iskopirati tekst ispod. Obraditi pažnju na to da, kada se fajl otvori, prikazaće se obično izgled aplikacije. Na slici ispod vidimo neke komande u gornjem desnom uglu. Potrebno je kliknuti Code da bi nam se prikazao sadržaj XML fajla kojeg smo otvorili. Dobra je praksa i da se koristi Split opcija kako bismo istovremeno videli kako će naša aplikacija da izgleda.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" /> </LinearLayout>
Linear Layout je najjednostavniji layout. U njemu se svi elementi postavljaju vertikalno ili horizontalno u redosledu u kojem deklarišemo elemente. Ako se ne navede orijentacija, podrazumeva se da je vertikalna (elementi se postavljaju jedni ispod drugih). Može se orijentacija promeniti da bude horizontalna podešavanjem android:orientation atributa na sledeći način:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation = "horizontal" tools:context=".MainActivity" />
Pogledajmo android:layout_width parametar. Njega smo postavili na match_parent. U opštem slučaju, to znači da će širina objekta biti ista kao i kod roditeljskog elementa (onog u kojem je naš objekat sadržan). Pošto nema roditelja od Linear Layout, onda se za roditelja uzima širina ekrana, što znači da će ovde Linear Layout uzeti širinu ekrana.
Parametar android:height je podešen na wrap_content, što obezbeđuje da će Linear Layout biti one visine koliko zauzimaju sva njegova deca ukupno.
Prvo dete koje smo definisali je TextView. TextView je obična labelica sa tekstom koji se nalazi u atributu android:text. Oba atributa za veličinu smo podesili na wrap:content da bi labelica uvek bila onoliko dugačka koliko je i njen tekst.
Dugme se dodaje na korisnički interfejs tako što se pokreće naredba Button. Recimo, na sledećem primeru na naš Linear Layout dodajemo dugme koje će biti jednake veličine kao i tekst koji se na njemu nalazi.
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Ja sam dugme" />
Dugme možemo, recimo, postaviti na desnu stranu ekrana. Potrebno je dodati vrednost android:layout_gravity atributa. On može imati vrednost left, right i center, top i bottom. Osim ovih, korisni su i center_horizontal i center_vertical. Više o ovom atributu može se naći na stranici dokumentacije. Dakle, sada naš kod za dugme izgleda ovako:
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Ja sam dugme" android:layout_gravity = "right" />
Edit View je objekat na kojem je dozvoljeno korisniku da piše tekst. Ovo može biti korisno zbog interkacije sa korisnikom. EditView ima slične atribute kao i TextView i Button. Korisno je videti na jednom primeru primenu sva tri. Na primer, ako želimo da sastavimo aplikaciju za slanje mejlova, možemo sledećim kodom zadati izgled kao na slici ispod.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="16dp" android:paddingRight="16dp" android:orientation="vertical" > <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="To:" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Subject:" /> <EditText android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="top" android:hint="Message:" /> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:layout_gravity="right" android:text="Send:" /> </LinearLayout>
Niska koja se doda uz android:hint će stajati dok korisnik ne počne da unosi svoj tekst.
Trenutno ne možemo ništa uraditi sa ovim, a to je zbog toga što nije još isprogramirano ponašanje programa kada se klikne na dugme, unosi tekst i slično.
Dosadašnji način na koji smo uređivali niske je nepraktičan. Recimo, zamislimo situaciju u kojoj treba instancirati 5 objekata sa istim tekstom koji može, pritom, da bude i veoma dugačak. Tada bismo morali, u svakom od tih elemenata, instancirati parametar android:text na istu nisku. U slučaju promene teksta, neisplativo je u svakom elementu menjati parametar android:text. Iz tog razloga, u direktorijumu
Recimo, na primeru našeg dugmeta, dovoljno je samo u strings.xml dodati liniju koda:
<resources> <string name="app_name">My Application</string> <string name="dugme_label">Ja sam dugme!</string> </resources>
I potom u android:text parametru se pozvati na nisku na sledeći način:
android:text = "@string/dugme_label"
Sve što radi naš program, nalazi se u src/main/java/MainActivity.kt fajlu, unutar metoda onCreate. U tom metodu će se uvek nalaziti pozivi dve metode. Prvi metod koji se poziva je metod natklase, a drugi je metod koji postavlja izgled našeg prozora. Ta dva metoda ne treba menjati.
Da bismo definisali ponašanje našeg dugmeta, moramo prvo napraviti objekat koji se povezuje sa dugmetom kojeg smo definisali u XML fajlu. Najpre, da bi kompajler znao o kojem je dugmetu reč (može ih biti više u aplikaciji), moramo dugmetu da dodamo nekakav ID da bi se razlikovao od svih ostalih. U XML fajlu nađemo dugme čije ponašanje hoćemo da definišemo i definišemo mu parametar android:id kao u sledećem primeru:
android:id = "@+id/dugme1"
Prvi deo je @+id koji govori da je u pitanju ID, dok je ID dugme1. Sada možemo instancirati dugme u našem kodu pomoću funkcije findViewById. Funkcija prima ID objekta i vraća nam objekat na koji referiše. Na prethodnom primeru, to izgleda ovako:
val dugme1 : Button = findViewById(R.id.dugme1)
Ponašanje dugmeta se definiše na osnovu metoda setOnClickListener na sledeći način:
val dugme1 : Button = findViewById(R.id.dugme1) dugme1.setOnClickListener { naredbe... }
Naredbe možemo direktno zadati unutar vitičastih zagrada, a možemo definisati funkciju koja će sve njih da sadrži. Drugi pristup je dobar kada zbog preglednosti. Recimo, klikom na dugme, ispisujemo korisniku poruku da je dugme pritisnuto. Poruke ovakvog tipa se mogu ispisivati korišćenjem metoda makeText klase Toast. Metod makeText prima tri argumenta: kontekst, poruku i dužinu poruke. Kontekst je element klase Context i on nam omogućava komunikaciju sa Android OS, kao i da dobijamo trenutne informacije od Android OS. U našem slučaju, možemo koristiti ključnu reč this, jer je naša klasa MainActivity podklasa od AppCompatActivity čija je nadklasa Context. Dužina poruke se zadaje kao pozitivan ceo broj i preporučeno je da se za to koriste konstante klase Toast. Kada se izvrši metod makeText, vraća se referenca na Toast objekat koji je taj metod instancirao. Da bi se poruka prikazala, potrebno je sada reći tom objektu da je prikaže. Recimo, to bi izgledalo ovako u kodu:
val dugme1 : Button = findViewById(R.id.dugme1) dugme1.setOnClickListener { val toast = Toast.makeText(this, "Pritisnuto dugme1", Toast.LENGTH_SHORT) toast.show() }
val dugme1 : Button = findViewById(R.id.dugme1) dugme1.setOnClickListener { Toast.makeText(this, "Pritisnuto dugme1", Toast.LENGTH_SHORT).show() }
Osim ispisivanja Toast poruka, moguće je i druge stvari raditi. Recimo, moguće je menjati tekst elementima. Recimo, na sledećem primeru možemo da beležimo na dugmetu koliko je puta kliknuto:
val dugme1 : Button = findViewById(R.id.dugme1) var count = 0 // u pocetku je dugme 0 puta pritisnuto dugme1.setOnClickListener { count++ dugme1.text = count.toString() }
Osim ispisa podataka, možemo pročitati ono što korisnik ispiše u EditView polju pritiskom na dugme. Recimo, želimo da dodamo sledeću funkcionalnost:
val dugme1 : Button = findViewById(R.id.dugme1) dugme1.setOnClickListener { val edit1 : EditView = findViewById(R.id.edit1) val text1 : TextView = findViewById(R.id.text1) if (edit1.text.isEmpty()) { text1.text = "Empty" } else { text1.text = edit1.text } }