Podstawowe layouty

Jak już zapewne sami zaważyliście pliki z layoutem można otwierać na co najmniej dwa sposoby. Pierwszym, edytorem wizualnym, posługiwaliśmy sie ostatnio. Pora na drugi. Otwórzmy sobie nasz plik z poprzedniej lekcji wybierając tryb xml.

widgety

Powinniśmy zobaczyć coś takiego:

<?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:orientation="vertical" >
  
      <TextView
          android:id="@+id/nazwa"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/javastart"
          android:textAppearance="?android:attr/textAppearanceLarge" />
  
      <TextView
          android:id="@+id/imie_label"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/imie" />
  
      <EditText
          android:id="@+id/imie"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:inputType="textPersonName" >
  
          <requestFocus />
      </EditText>
  
      <TextView
          android:id="@+id/textView3"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/plec" />
  
      <RadioGroup
          android:id="@+id/plec"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" >
  
          <RadioButton
              android:id="@+id/radio0"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:checked="true"
              android:text="@string/kobieta" />
  
          <RadioButton
              android:id="@+id/radio1"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/mezczyzna" />
  </RadioGroup>
  
      <TextView
          android:id="@+id/textView4"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/ocena" />
  
      <RatingBar
          android:id="@+id/ocena"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:numStars="5" />
  
      <Button
          android:id="@+id/przycisk"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="bottom"
          android:text="@string/ok" />
  
  </LinearLayout>

Jak widać każdemu elementowi przypada kawałek odpowiadającemu mu kodu. Jest to dosyć czytelne, ponieważ dokładnie widać gdzie zaczyna się definiowanie parametrów danego elementu.

Niektórzy nie używają w ogóle trybu wizualnego, twierdząc, ze generuje on zbędny kod. Osobiście sie z nimi nie zgadzam. Kreator umożliwia w bardzo łatwy sposób stworzenie pożądanego layoutu.

Dzisiaj pokusimy sie o bardziej zaawansowany widok. W celu jego zrealizowania potrzebne będzie nam zrozumienie layoutów. Jeśli przejdziemy z powrotem do widoku wizualnego, to w wigetach możemy zauważyć zakładkę layout.

paleta widgetów

Samo przeciąganie layoutu na ekran właściwie nic nie daje, ponieważ jest to tylko pojemnik na właściwą zawartość. Zależnie od wybranego layoutu wrzucone w niego elementy będą układać sie z góry na dół, od prawej od lewej, albo będą zachowywały się zależnie od innego elementu. Ich istotna właściwością jest to, ze można wrzucać jeden layout do drugiego.

Linear Layout (Horizontal)

Elementy w tym layoucie będą się układać od lewej do prawej.

linear layout horizontal
<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="match_parent"
      android:orientation="horizontal" >
  
      <Button
          android:id="@+id/button1"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Button" />
  
      <Button
          android:id="@+id/button2"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Button" />
  
      <Button
          android:id="@+id/button3"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Button" />
  
      <Button
          android:id="@+id/button4"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Button" />
  
      <Button
          android:id="@+id/button5"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Button" />
  
  </LinearLayout>

Linear Layout (Vertical)

Elementy w tym layoucie będą się układać z góry na dół.

linear layout vertical
<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="match_parent"
      android:orientation="vertical" >
  .
  .
  .
  
  </LinearLayout>

Jak widać, jedyna zmiana to dodatkowy atrybut android:orientation="vertical" dla LinearLayout.

Relative layout

Tutaj sprawa jest ciekawsza. Elementy układają się zależnie od innych elementów. Przyjrzyjmy się temu dokładniej.

Najpierw ustalmy RelativeLayout na całym ekranie - najlepiej skopiować poniższy kod.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent" >
  
  </RelativeLayout>

Przy przeciąganiu elementu pojawiają się strzałki wskazujące względem jakiego innego elementu zostanie on ustawiony. Ustawmy sobie kilka przycisków.

relative layout relativelayout relativelayout 2

Zajrzyjmy teraz do tego co zostało wygenerowane w pliku XML.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent" >
  
      <Button
          android:id="@+id/button1"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_alignParentTop="true"
          android:layout_marginLeft="92dp"
          android:layout_marginTop="81dp"
          android:text="Button" />
  
      <Button
          android:id="@+id/button2"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignLeft="@+id/button1"
          android:layout_below="@+id/button1"
          android:layout_marginTop="130dp"
          android:text="Button" />
  
      <Button
          android:id="@+id/button3"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_below="@+id/button1"
          android:layout_marginLeft="48dp"
          android:layout_marginTop="60dp"
          android:layout_toRightOf="@+id/button2"
          android:text="Button" />
  
  </RelativeLayout>

Pojawiają się nowe atrybuty.

Te z informacją o odległości (zauważcie, że stosowanie jest dp, a nie px - informacja na ten temat na końcu artykułu)

android:layout_marginLeft   // dodatkowa odległość po lewej stronie
android:layout_marginTop   // dodatkowa odległość od góry

No i atrybuty relacyjne, wskazujące od których elementów zależą

android:layout_alignParentLeft  // zależne od lewej strony kontenera (layoutu) w którym się znajduje
android:layout_alignParentTop  // zależne od prawej strony kontenera (layoutu) w którym się znajduje
android:layout_below     // znajduje się pod wskazanym elementem
android:layout_toRightOf    // znajduje się po prawej stronie wskazanego elementu

Spróbuj teraz przemieścić pierwszy przycisk. Efekt - wszystko się przesunęło. Niestety nie ma na to lekarstwa i najlepszym sposobem zarządzania RelativeLayoutem jest wpisywanie go z poziomu XML.

Frame Layout

Używany dużo rzadziej niż inne layouty. Służy głównie do przechowywania tylko jednego widoku, który ma być widoczny nad innym.

tekst na gorze
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent" >
  
      <ImageView
          android:id="@+id/imageView1"
          android:layout_width="wrap_content"
          android:layout_height="match_parent"
          android:scaleType="centerCrop"
          android:src="@drawable/tlo" />
  
      <TextView
          android:id="@+id/textView1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="top"
          android:text="Text na górze"
          android:textAppearance="?android:attr/textAppearanceLarge"
          android:textColor="#ff0000"
          android:textStyle="bold" />
  
      <TextView
          android:id="@+id/textView2"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="bottom"
          android:text="Tekst na dole"
          android:textAppearance="?android:attr/textAppearanceLarge"
          android:textColor="#ff0000" />
  
  </FrameLayout>

Tutaj nowym elementem może być ImageView. Jest to kontrolka służąca do wyświetlania grafik. Przed jej użyciem należy umieścić swój obrazek w forderze /res/drawable, a następnie wystarczy przeciągnąć kontrolkę ImageView na ekran, a system sam zapyta nas jakiej grafiki chcemy użyć. Wybieramy odpowiednią i gotowe.

Dodatkowe informacje

Przy projektowaniu ekranu należy zwrócić szczególną uwagę na to, że użytkownicy naszej aplikacji będą korzystali z niej na szerokiej gamie urządzeń z rożnymi rozdzielczościami. Dlatego właśnie w Androidzie nie stosujemy pikseli (px) tylko dp (Density-independent pixel).

Jego wielkość jest zależna od wielkości ekranu, co zapewnia nam, ze aplikacja będzie wyglądała niemal identycznie na wszystkich urządzeniach.

Pozostaje jeszcze kwestia zmiany orientacji ekranu. Tutaj sprawa nie jest taka prosta. Ja z reguły radze sobie w taki sposób, ze blokuje możliwość obrotu ekranu. Jest to podejście bardzo nieeleganckie. Optymalnym rozwiązaniem byłoby stworzenie osobnych layoutu dla orientacji pionowej i poziomej. Następnie wystarczy tylko przechwycić wydarzenie zmiany orientacji i wczytać alternatywny layout. Nie jestem jeszcze do końca przekonany co do takie podejścia. Postaram sie douczyć i w najbliższym czasie napisać o tym osobny artykuł.

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.

Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.

Mateusz

" /res/drawabke" wkradła się literówka. Poza tym świetny artykuł :)

Marcin Kunert

Hej Mateusz, dzięki za info. Widzę, że uważnie czytałeś. Poprawiłem :)

Tomek

Świetne artykuły, jest jakaś konkretna częstotliwość z jaką je wrzucasz? Czy piszesz po prostu w wolnych chwilach?

Marcin Kunert

W wolnych chwilach, których ostatnio coraz mniej. Spróbuję się zmobilizować i coś niebawem dodać.

Lolo

Można jakoś napisać aplikację by nie miała okna ale, żeby można było np. wyświetlać toasty?