Korisnički interfejs

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>

Linear Layout i TextView

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

<?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.

Savet! Korisno je, kada imamo horizontalnu orijentaciju, da širina bude postavljena na wrap_content, a visina na match_parent. Na taj način, naš Linear Layout će uvek biti dovoljno veliki u širini, kao što se njegova deca raspoređuju.

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.

Veličine su se mogle i drugačije zadati. Podržane su u Androidu veličine poput inča (in), milimetra (mm), piksela (px), kao i dp i sp veličina. Od svih ovih, možda je najkorisnija sp, jer je relativna u odnosu na veličinu fonta na ekranu (1 sp = veličina fonta), što je veoma zato što veličine ekrana nisu iste.

Dugme

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

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>

Mail

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.

Uređivanje niski

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 src/main/res se nalazi XML fajl strings.xml. U tom fajlu smeštamo naše niske na koje potom prosleđujemo reference u našem activity_main.xml fajlu. Na taj način, dovoljno je samo promeniti nisku u strings.xml da bi se niska promenila.
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"

Interakcija

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)
Napomena! Ako se reč Button zacrveni, potrebno je uključiti klasu Button u naš projekat. Ovaj deo posla radi sam Android Studio za nas. Dovoljno je kliknuti na crvenu lampicu i izabrati opciju Import ili pritisnuti Alt+Enter dok držimo miš iznad reči Button.

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()
}
U skraćenoj formi, moglo je stajati i:
val dugme1 : Button = findViewById(R.id.dugme1)
dugme1.setOnClickListener {
  Toast.makeText(this, "Pritisnuto dugme1", Toast.LENGTH_SHORT).show()
}
Više od klasi Toast i metodi makeText može se naći na sledećem linku.

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:

  1. Ako smo išta napisali u EditView, onda da se to prepiše u neki TextView
  2. Ako nismo ništa napisali u EditView, onda da se u TextView ispiše poruka "Empty".
To bi u kodu izgledalo ovako:

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
  }
}