Tworzenie prostego interfejsu użytkownika

03 listopada 2012
1 gwiadka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek

Budowa graficznego interfejsu użytkownika aplikacji Android opiera się na hierarchii obiektów View i ViewGroup. Obiekty View są zazwyczaj widocznymi elementami interfejsu, np. przyciskami i polami tekstowymi, natomiast obiekty ViewGroup to niewidoczne kontenery określające sposób rozmieszczenia elementów widoków potomnych, np. w siatce albo pionowej liście.

Dostępna jest składnia XML odpowiadająca podklasom klas View i ViewGroup, dzięki czemu interfejs użytkownika można zdefiniować przy użyciu hierarchii elementów XML.

Alternatywne układy

Możliwość definiowania układu interfejsu użytkownika przy użyciu XML-a zamiast kodu programistycznego jest korzystne z kilku powodów, z których najważniejszym jest możliwość tworzenia różnych układów dla ekranów o różnych rozmiarach. Można na przykład utworzyć dwie wersje układu i nakazać systemowi stosowanie jednego na „małych” ekranach, a drugiego — na „dużych”. Więcej informacji na ten temat znajduje się w lekcji o obsłudze różnych urządzeń.

Drzewiasta struktura obiektów klasy ViewGroup zawierających obiekty klasy View

Rysunek 1. Ilustracja drzewiastej struktury obiektów klasy ViewGroup zawierających obiekty klasy View

W tej lekcji dowiesz się, jak utworzyć przy użyciu XML-a układ zawierający pole tekstowe i przycisk. W następnej lekcji dowiesz się, jak reagować na naciśnięcie tego przycisku poprzez wysłanie zawartości pola tekstowego do innej aktywności.

Tworzenie układu liniowego

Otwórz plik activity_main.xml znajdujący się w katalogu res/layout/.

Domyślnie dodany do projektu szablon BlankActivity zawiera plik activity_main.xml, który z kolei zawiera widok główny RelativeLayout i widok potomny TextView.

Najpierw usuń element <TextView>, a następnie nazwę elementu <RelativeLayout> zmień na <LinearLayout>. Później dodaj atrybut android:orientation i przypisz mu wartość "horizontal". Teraz cały kod powinien wyglądać następująco:

<?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="match_parent"
    android:orientation="horizontal" >
</LinearLayout>

LinearLayout to grupa widoków (podklasa klasy ViewGroup) rozmieszczająca widoki potomne w pionie lub poziomie, zgodnie z ustawieniem atrybutu android:orientation. Widoki potomne widoku LinearLayout na ekranie są wyświetlane w kolejności zdefiniowania w pliku XML.

Dwa pozostałe atrybuty, android:layout_width i android:layout_height, są wymagane we wszystkich widokach i określają ich wymiary.

Ponieważ LinearLayout to główny widok układu, powinien on wypełniać cały obszar dostępny aplikacji na ekranie . Aby tak było, należy szerokość i wysokość ustawić na "match_parent". Wartość ta oznacza, że widok powinien rozciągać się w poziomie i pionie na całą szerokość i wysokość widoku nadrzędnego.

Więcej informacji na temat własności układów można znaleźć w poradniku dotyczącym Układów.

Dodawanie pola tekstowego

Aby utworzyć pole tekstowe, należy w elemencie <LinearLayout> utworzyć element <EditText>.

Jak w przypadku każdego obiektu klasy View, własności obiektu EditText należy zdefiniować przy użyciu odpowiednich atrybutów XML. Poniżej przedstawione jest poprawne umiejscowienie tego kodu w elemencie <LinearLayout>:

    <EditText android:id="@+id/edit_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="@string/edit_message" />

Opis atrybutów:

android:id

Unikalny identyfikator dla widoku, przy użyciu którego można odnosić się do tego obiektu w kodzie aplikacji, np. aby odczytać ten obiekt i nim manipulować (przeczytasz o tym w następnej lekcji).

Znak @ jest wymagany zawsze, gdy odnosimy się do obiektu zasobu wewnątrz pliku XML. Po nim powinny znajdować się typ zasobu (w tym przypadku id), ukośnik oraz nazwa zasobu (edit_message).

Znak + przed typem zasobu jest wymagany tylko przy pierwszej definicji identyfikatora zasobu. Podczas kompilacji programu, narzędzia SDK używają tego identyfikatora do utworzenia nowego identyfikatora zasobu w pliku gen/R.java projektu, który odnosi się do elementu EditText. Po zadeklarowaniu identyfikatora zasobu w ten sposób, w kolejnych odniesieniach do niego nie trzeba już używać znaku plusa. Znak plus jest wymagany tylko, gdy określany jest identyfikator nowego zasobu i nie jest potrzebny dla konkretnych zasobów, takich jak łańcuchy i układy. Więcej informacji na temat obiektów zasobów znajduje się w bocznej ramce.

android:layout_width i android:layout_height
Zamiast określać konkretne wartości szerokości i wysokości, za pomocą wartości "wrap_content" można sprawić, że widok będzie dopasowywał się rozmiarem do treści. Gdyby zamiast tego użyto wartości "match_parent", wówczas element EditText wypełniałby ekran, ponieważ byłby dopasowany rozmiarem do wymiarów rodzica, którym jest LinearLayout. Więcej informacji na temat własności układów można znaleźć w poradniku dotyczącym układów.
android:hint

Jest to domyślny tekst wyświetlany, gdy pole tekstowe jest puste. Zamiast konkretnego tekstu można wpisać wartość "@string/edit_message" odnoszącą się do zasobu łańcuchowego znajdującego się w osobnym pliku. Ponieważ odwołanie jest do konkretnego zasobu (nie identyfikatora), nie trzeba dodawać znaku plus. Ponieważ jednak wskazany zasób łańcuchowy nie jest jeszcze zdefiniowany, zostanie wyświetlone powiadomienie o błędzie. Wkrótce to naprawimy definiując ten łańcuch.

Dodawanie zasobów łańcuchowych

Tekst dodawany do interfejsu użytkownika zawsze powinien być definiowany w postaci zasobów łańcuchowych. Dzięki temu wszystkimi tekstami używanymi w interfejsie można zarządzać w jednym miejscu, co ułatwia pracę i modyfikowanie programu. Ponadto umieszczenie łańcuchów tekstowych na zewnątrz aplikacji umożliwia jej lokalizację w różnych językach polegającą na podaniu alternatywnych definicji dla każdego zasobu łańcuchowego.

Domyślnie twój projekt Android zawiera plik zasobów łańcuchowych o nazwie res/values/strings.xml. Otwórz go i usuń z niego element <string> o nazwie hello_world. Następnie dodaj nowy element <string> o nazwie edit_message i w jego treści wpisz tekst Wpisz wiadomość.

Dodatkowo, skoro już jesteś w tym pliku, wpisz łańcuch Wyślij dla przycisku o nazwie button_send, który wkrótce dodasz do projektu.

Teraz plik strings.xml powinien zawierać następujący kod:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My First App</string>
    <string name="edit_message">Enter a message</string>
    <string name="button_send">Send</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">MainActivity</string>
</resources>

Więcej informacji na temat sposobów wykorzystania zasobów łańcuchowych do lokalizacji programów znajdziesz w lekcji o obsłudze różnych urządzeń.

Dodawanie przycisków

Teraz w układzie bezpośrednio za elementem <EditText> dodaj element <Button>:

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send" />

Wysokość i szerokość są ustawione na wrap_content, dzięki czemu przycisk dopasowuje się rozmiarem do znajdującego się na nim tekstu. Przycisk ten nie musi mieć atrybutu android:id, ponieważ nie będziemy się do niego odwoływać z kodu aktywności.

Tworzenie pól tekstowych o szerokości ekranu

Aktualnie elementy EditText i Button dopasowują się rozmiarami do znajdującej się w nich treści, jak widać na rysunku 2.

Elementy EditText i Button mają szerokości ustawione na wrap_content

Rysunek 2. Elementy EditText i Button mają szerokości ustawione na wrap_content

Rozwiązanie to jest dobre dla przycisku, ale nie dla pola tekstowego, w którym użytkownik może wpisywać teksty o różnej długości. Dlatego lepiej by było wypełnić nieużywaną cześć ekranu tym polem. Można to zrobić w układzie LinearLayout przy użyciu własności wagi, którą definiuje się za pomocą atrybutu android:layout_weight.

Wartość ta jest liczbą określającą, ile miejsca ma zająć każdy z widoków względem ilości miejsca zajętego przez widoki siostrzane. Jest to coś podobnego do przepisów na drinki: „2 części wódki, 1 część likieru kawowego” oznacza, że 2/3 drinka stanowi wódka. Jeśli na przykład jednemu widokowi zostanie przypisana waga 2, a drugiemu 1, to suma ich wyniesie 3, a zatem pierwszy widok będzie zajmował 2/3 dostępnej przestrzeni, natomiast drugi — resztę. Jeśli dodamy do tego trzeci widok i nadamy mu wagę 1, wówczas pierwszy widok (o wadze 2) będzie zajmował 1/2 dostępnej przestrzeni, natomiast pozostałe dwa widoki po 1/4.

Domyślnie każdy widok ma wagę 0, a więc jeśli przypisze się wagę wyższą od 0 tylko jednemu widokowi, zajmie on całą przestrzeń, jaka pozostanie dostępna po przydzieleniu każdemu widokowi miejsca, które jest przez niego wymagane. Aby zatem wypełnić pozostającą wolną przestrzeń elementem EditText w naszym układzie, nadajemy mu wagę 1, a wagę przycisku pozostawiamy bez zmian.

    <EditText
        android:layout_weight="1"
        ... />

Aby poprawić wydajność układu, gdy określi się wagę, należy szerokość elementu EditText zmienić na zero (0dp). Ustawienie szerokości na zero sprawia, że układ jest bardziej wydajny, ponieważ wartość wrap_content określająca szerokość zmusza system do obliczania szerokości, co jest niepotrzebne, gdyż później i tak waga zmusza go po raz kolejny do obliczenia szerokości elementu mającego wypełniać pozostającą wolną przestrzeń.

    <EditText
        android:layout_weight="1"
        android:layout_width="0dp"
        ... />

Na rysunku 3. przedstawiono efekt przypisania wagi elementowi EditText.

Element EditText ma przypisaną wagę pozwalającą mu zająć całą wolną przestrzeń w widoku LinearLayout

Rysunek 3. Element EditText ma przypisaną wagę pozwalającą mu zająć całą wolną przestrzeń w widoku LinearLayout

Poniżej przedstawiony jest kod, który powinien znajdować się w pliku układu:

<?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="match_parent"
    android:orientation="horizontal">
    <EditText android:id="@+id/edit_message"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="@string/edit_message" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send" />
</LinearLayout>

Układ ten jest stosowany przez domyślną klasę Activity wygenerowaną przez narzędzia SDK podczas tworzenia projektu. Dzięki temu można już uruchomić aplikację, aby zobaczyć, jak działa:

  • W Eclipse kliknij przycisk Start na pasku narzędzi.
  • W wierszu poleceń przejdź do katalogu głównego projektu i wykonaj następujące polecenie:

    ant debug
    adb install bin/MyFirstApp-debug.apk
    

W następnej lekcji nauczysz się reagować na zdarzenia naciśnięcia przycisków, odczytywać tekst z pól tekstowych, rozpoczynać nowe aktywności i wiele więcej.

Autor: Google

Źródło: https://developer.android.com/training/basics/firstapp/building-ui.html

Tłumaczenie: Łukasz Piwko

Treść tej strony dostępna jest na zasadach licencji CC BY 2.5

2 komentarze

  1. Udało mi sie rozwiązać problem, w pliku activity_main.xml w wierszu: <EditText android:id="@+id/edit_message" zamiast edit_message wpisałam container i poszło.

    Teraz tylko nie moge uruchomić aplikacji na tablecie, wyskakuje na urządzeniu info, że apliakcja została zatrzymana… ???

    Odpowiedz
  2. Witam,
    Mam problem, nie moge uruchomić programu, gdyż wyskakuje błąd w pliku MainActivity.java , konkretnie w linijce:
    .add(R.id.container, new PlaceholderFragment()).commit();

    „container cannot be resolved or is not a field”.

    W innej aplikacji jest ydentyczny kod i wszystklo jest ok.

    Nadmienię, że przed tym, musiałam edytować plik fragment_main.xml, gdyż wyskakiwał mi błąd w linijce:
    android:text=”@string/hello_world” />

    hello_world zamieniłam na edit_message i juz było ok.

    chyba że tutaj coś sknociłam.

    Bardzo bym prosiła o pomoc.

    A tak przy okazji, fajny kurs, pierwszy na jaki natrafiłąm, w którym wyjaśniane jest wszystko krok po kroku :)

    Odpowiedz

Dyskusja

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *