Tworzenie komponentów widoku niestandardowego

Wypróbuj sposób tworzenia wiadomości
Jetpack Compose to zalecany zestaw narzędzi UI na Androida. Dowiedz się, jak korzystać z układów w funkcji Utwórz

Android oferuje zaawansowany i zaawansowany model składowy do tworzenia interfejsu użytkownika oparty na podstawowe klasy układu View i ViewGroup Platforma ta obejmuje różnych gotowych podklas View i ViewGroup – nazywanych widżetami układów, których możesz używać do tworzenia interfejsu użytkownika.

Częściowa lista dostępnych widżetów obejmuje Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery Spinner, a tym bardziej specjalnym AutoCompleteTextView, ImageSwitcher, TextSwitcher.

Dostępne układy to: LinearLayout, FrameLayout, RelativeLayout, i inne. Więcej przykładów: Typowe układy.

Jeśli żaden z gotowych widżetów ani układów nie spełnia Twoich wymagań, możesz tworzyć własne Podklasa View. Jeśli chcesz wprowadzić niewielkie poprawki w istniejącym widżecie lub układu, możesz utworzyć klasyfikację podrzędną widżetu lub układu i zastąpić jego metody.

Tworzenie własnych podklas View zapewnia precyzyjną kontrolę nad wyglądem funkcji elementu na ekranie. Aby zorientować się w możliwościach kontroli w widokach niestandardowych, skorzystaj z tych co możesz dzięki nim zrobić:

  • Możesz utworzyć całkowicie renderowany niestandardowo typ View, na przykład „wolumin „sterowanie” renderowany z użyciem grafiki 2D, który przypomina analogowy elektroniczny element sterujący.
  • Możesz połączyć grupę komponentów View w 1 komponent. Oto niektóre z nich: tworząc pole kombi (kombinację wyskakującej listy i pola tekstowego do wpisania), element sterujący selektorem podwójnej przestrzeni (panel lewy i prawy z listą który element znajduje się na której liście) itd.
  • Możesz zastąpić sposób renderowania komponentu EditText na ekranie. Przykładowa aplikacja NotePad sprawdza się w przypadku tworzenia strony notatnika z liniami.
  • Możesz rejestrować inne zdarzenia, np. naciśnięcia klawiszy, i obsługiwać je w niestandardowy sposób, jak w przypadku gry.

W sekcjach poniżej wyjaśniamy, jak tworzyć widoki niestandardowe i używać ich w swojej aplikacji. Dla: szczegółowe informacje na ten temat znajdziesz w View zajęcia.

Podstawowe podejście

Oto ogólne omówienie informacji, które musisz wiedzieć, aby utworzyć własny View komponenty:

  1. Rozszerz istniejącą klasę lub podklasę View o własne zajęcia.
  2. Zastąp niektóre metody z klasy nadrzędnej. Metody klasy superklasy, od których rozpoczyna się zastępowanie on, na przykład: onDraw(), onMeasure(), oraz onKeyDown() Jest podobny do zdarzeń on w: Activity lub ListActivity, które Ty dla cyklu życia i innych punktów zaczepienia funkcjonalności.
  3. Użyj nowej klasy rozszerzenia. Po zakończeniu możesz używać nowej klasy rozszerzenia zamiast widoku, na podstawie którego zostały utworzone.
.

W pełni dostosowane komponenty

Możesz tworzyć w pełni dostosowane komponenty graficzne, które wyświetlają się w pobliżu. Potrzebujesz graficznego miernika VU, który wygląda jak stary wskaźnik analogowy, albo widoku tekstowego do wspólnego śpiewania. w którym odbijająca się piłka przesuwa się wzdłuż słów, gdy śpiewasz razem z urządzeniem do karaoke. Więcej informacji czego nie będą mogli wykonać wbudowane komponenty, niezależnie od tego, jak je połączysz.

Na szczęście możesz tworzyć komponenty, które wyglądają i działają w dowolny sposób – są one wyobraźnię, rozmiar ekranu i dostępną moc obliczeniową, pamiętając, że aplikacja może działać na czymś o znacznie mniejszej mocy niż komputer stacji roboczej.

Aby utworzyć w pełni dostosowany komponent, weź pod uwagę te kwestie:

  • Najbardziej ogólny widok, który możesz rozszerzyć, to View, więc zazwyczaj zaczynasz od rozszerzenia aby utworzyć nowy superkomponent.
  • Można dostarczyć konstruktor, który może pobierać atrybuty i parametry z pliku XML oraz wykorzystują takie atrybuty i parametry, jak kolor i zasięg miernika VU, czy szerokość i tłumienie drgań igły.
  • Prawdopodobnie warto utworzyć własne detektory zdarzeń, akcesory właściwości i modyfikatory, a także bardziej zaawansowane zachowanie w klasie komponentu.
  • Prawie na pewno chcesz zastąpić ustawienie onMeasure() i prawdopodobnie konieczne będzie zastąp onDraw(), jeśli komponent ma coś wyświetlać. Choć w obu działach działanie domyślne, domyślne ustawienie onDraw() nie wykonuje żadnych działań, a domyślne onMeasure() zawsze ustawia rozmiar 100 x 100, którego prawdopodobnie nie chcesz używać.
  • W razie potrzeby możesz też zastąpić inne metody on.

Rozszerzaj funkcje onDraw() i onMeasure()

Metoda onDraw() generuje Canvas, za pomocą których możesz możesz zaimplementować, co chcesz: grafikę 2D, inne standardowe lub niestandardowe komponenty, styl tekstu lub co tylko przyjdzie Ci do głowy.

onMeasure() bardziej się angażuje. onMeasure() to kluczowy element umowy renderowania między komponentem a jego kontenerem. onMeasure() musi być można więc zastąpić, aby uzyskać precyzyjne i wydajne raportowanie pomiarów części składowych. To jest nieco bardziej skomplikowane przez wymagania dotyczące limitów określone przez wydawcę nadrzędnego, który jest przekazywany do onMeasure(), a przez wymaganie wywołania funkcji setMeasuredDimension() z mierzoną szerokością i wysokością po ich osiągnięciu obliczonych. Jeśli nie wywołasz tej metody z zastąpionej metody onMeasure(), co daje wyjątek w momencie pomiaru.

Ogólnie wdrożenie onMeasure() wygląda tak:

  • Zastąpiona metoda onMeasure() jest wywoływana wraz z informacją o szerokości i wysokości specyfikacji, które są traktowane jako wymagania dotyczące ograniczeń szerokości i wysokości stosowane pomiary. widthMeasureSpec i heightMeasureSpec są kodami całkowitymi reprezentującymi wymiary. Pełne omówienie rodzaju ograniczeń, których mogą wymagać te specyfikacje, można znaleźć w dokumentacji referencyjnej w View.onMeasure(int, int) W tej dokumentacji opisano również cały proces pomiaru.
  • Metoda onMeasure() komponentu oblicza szerokość i wysokość, które są wymagane do renderowania komponentu. Musi zachowywać zgodność z zaakceptowaną specyfikacją chociaż może ich przekroczyć. W takim przypadku rodzic może zdecydować, co zrobić, w tym przycinać, przewijać, zgłaszać wyjątek czy prosić onMeasure() o ponowną próbę, np. z innymi specyfikacjami.
  • Przy obliczaniu szerokości i wysokości wywołaj funkcję setMeasuredDimension(int width, int height) z obliczonym pomiarów. Jeśli tego nie zrobisz, zostanie utworzony wyjątek.

Oto podsumowanie innych standardowych metod, które platforma wywołuje w przypadku wyświetleń:

Kategoria Metody Opis
na podstawie trendów Konstruktorki Istnieje forma konstruktora, która jest wywoływana podczas tworzenia widoku na podstawie kodu. i formularz, który jest wywoływany, gdy widok zostanie powiększony z pliku układu. Druga forma analizuje i stosuje atrybuty zdefiniowane w pliku układu.
onFinishInflate() Wywoływana po wyświetleniu i wszystkich jego elementach podrzędnych są powiększone z pliku XML.
Układ onMeasure(int, int) Wywoływana w celu określenia wymagań dotyczących rozmiaru dla tego widoku i wszystkich jego dzieci.
onLayout(boolean, int, int, int, int) Wywoływana, gdy ten widok musi przypisać rozmiar i pozycję wszystkim jego elementom podrzędnym.
onSizeChanged(int, int, int, int) Wywoływana po zmianie rozmiaru tego widoku.
Rysunek onDraw(Canvas) Wywoływane, gdy widok musi wyrenderować swoją treść.
Przetwarzanie zdarzeń onKeyDown(int, KeyEvent) Wywoływana po wystąpieniu zdarzenia wyłączenia.
onKeyUp(int, KeyEvent) Wywoływana po wystąpieniu kluczowego zdarzenia.
onTrackballEvent(MotionEvent) Wywoływane po wystąpieniu zdarzenia ruchu kulki.
onTouchEvent(MotionEvent) Wywoływane po wystąpieniu zdarzenia ruchu na ekranie dotykowym.
Ostrość onFocusChanged(boolean, int, Rect) Wywoływane, gdy widok zyskuje lub traci ostrość.
onWindowFocusChanged(boolean) Wywoływane, gdy okno zawierające widok zyskuje lub traci fokus.
Dołączanie onAttachedToWindow() Wywoływane, gdy widok jest dołączony do okna.
onDetachedFromWindow() Wywoływane, gdy widok zostaje odłączony od jego okna.
onWindowVisibilityChanged(int) Wywoływana po zmianie widoczności okna zawierającego widok.

Złożone elementy sterujące

Jeśli nie chcesz tworzyć całkowicie niestandardowego komponentu, ale wolisz umieścić z komponentu wielokrotnego użytku, który składa się z grupy dotychczasowych elementów sterujących, a następnie tworzy taki komponent. składnika (lub złożonej kontroli) może być najlepszy. Podsumowując, niesie to ze sobą o wiele więcej niepodzielne elementy sterujące lub widoki w logiczną grupę elementów, które można traktować jak jedną rzecz. Na przykład pole złożone może być kombinacją jednego pola EditText w jednym wierszu i przyległy przycisk z dołączoną listą. Jeśli użytkownik kliknie przycisk i wybierze pozycję listę, wypełnia pole EditText, ale użytkownik może też coś wpisać bezpośrednio do usługi EditText.

Na Androidzie łatwo dostępne są 2 inne widoki: Spinner oraz AutoCompleteTextView Tak czy inaczej, dobrym przykładem jest koncepcja pola kombi.

Aby utworzyć komponent złożony, wykonaj te czynności:

  • Podobnie jak w przypadku Activity, zastosuj metodę deklaratywnej (opartą na XML). aby utworzyć zawarte komponenty lub zagnieździć je automatycznie z poziomu kodu. zwykle punktem początkowym jest jakaś Layout, więc utwórz klasę, która wydłuża Layout W przypadku pola kombi możesz użyć LinearLayout z w orientacji poziomej. Możesz zagnieździć też inne układy wewnątrz, dzięki czemu komponent złożony złożone i ustrukturyzowane.
  • W konstruktorze nowej klasy wybierz parametry, których oczekuje superklasa, i przekaż je do konstruktora klasy nadrzędnej. Następnie możesz skonfigurować pozostałe widoki do użycia w nowym komponencie. W tym miejscu tworzysz pole EditText oraz z listą wyskakującą. Możesz wprowadzić do pliku XML własne atrybuty i parametry, który może wyciągać i używać konstruktora.
  • Opcjonalnie możesz utworzyć detektory zdarzeń, które mogą generować zawarte widoki. Na przykład detektor kliknięć elementu listy w celu zaktualizowania zawartości EditText po wybraniu listy.
  • Opcjonalnie możesz utworzyć własne właściwości z akcesorami i modyfikatorami. Na przykład niech Wartość EditText zostanie początkowo ustawiona w komponencie i wysłane zapytanie o jej zawartość, gdy niezbędną.
  • Opcjonalnie zastąp onDraw() i onMeasure(). Zwykle nie jest to konieczne, gdy: rozszerzając pole Layout, ponieważ układ ma zachowanie domyślne, które prawdopodobnie działa dobrze.
  • Opcjonalnie możesz zastąpić inne metody on, takie jak onKeyDown(), na przykład aby wybrać określone metody domyślnych wartości z wyskakującej listy w polu kombi po kliknięciu określonego klawisza.

Zastosowanie Layout jako podstawy dla elementów sterujących niestandardowych ma wiele zalet, w tym:

  • Możesz określić układ za pomocą deklaratywnych plików XML, tak jak w przypadku ekranu z aktywnością lub tworzyć widoki automatycznie i zagnieżdżać je w układzie z kodu.
  • Metody onDraw() i onMeasure() oraz większość pozostałych on działają prawidłowo, więc nie musisz ich zastępować.
  • Możesz szybko tworzyć dowolnie złożone widoki złożone i używać ich ponownie, jak gdyby były co najmniej jeden komponent.

Modyfikowanie dotychczasowego typu widoku

Jeśli istnieje komponent, który jest podobny do tego, co chcesz, możesz go rozszerzyć i zastąpić. zachowanie, które chcesz zmienić. Wszystko to, co robisz, zapewnia w pełni spersonalizowany komponentu, ale zaczynając od bardziej wyspecjalizowanej klasy w hierarchii View, działania, które pomogą Ci bezpłatnie.

Na przykład parametr Notatnik przykładowa aplikacja prezentuje wiele aspektów korzystania z platformy Android. Jedną z nich jest przedłużenie w widoku EditText, aby utworzyć notatnik z linią. Nie jest to idealny przykład, a interfejsy API to może się zmienić, ale pokazuje nasze zasady.

Zaimportuj przykładowy notatnik z NotePad do Android Studio lub przejrzyj używając podanego linku. W szczególności zobacz definicję słowa LinedEditText w NoteEditor.java. .

Oto kilka rzeczy, które warto wziąć pod uwagę w tym pliku:

  1. Definicja

    Klasa jest zdefiniowana w tym wierszu:
    public static class LinedEditText extends EditText

    LinedEditText jest zdefiniowana jako klasa wewnętrzna w elemencie NoteEditor aktywności, ale jest ona publiczna, więc można z niej korzystać jako NoteEditor.LinedEditText spoza klasy NoteEditor.

    Poza tym LinedEditText to static, co oznacza, że nie generuje tak zwanych „metod syntetycznych”, który umożliwia mu dostęp do danych z klasy nadrzędnej. Oznacza to, że działa jako osobna klasa, a nie coś ściśle powiązanego z funkcją NoteEditor. Jest to bardziej przejrzysty sposób tworzenia klas wewnętrznych, jeśli nie potrzebują dostępu do stanu z poziomu klasa zewnętrzna. Wygenerowana klasa jest mała i umożliwia łatwe korzystanie z niej zajęcia.

    LinedEditText rozszerza widok EditText, którego zakres można dostosować tę sprawę. Gdy skończysz, nowe zajęcia mogą zastąpić zwykłe EditText widok.

  2. Inicjowanie klasy

    Jak zawsze, pierwszy z nich jest super. To nie jest domyślny konstruktor, ale z parametrami. Element EditText jest tworzony z tymi parametrami, gdy jest nadwyżki z pliku układu XML. Konstruktor musi je wtedy pobrać i przekazać za pomocą konstruktora klasy nadrzędnej.

  3. Zastąpione metody

    Ten przykład zastępuje tylko metodę onDraw(), ale może to być konieczne innych użytkowników podczas tworzenia własnych komponentów niestandardowych.

    W tym przykładzie zastąpienie metody onDraw() pozwala pomalować niebieskie linie na obszar roboczy widoku EditText. Obszar roboczy jest przekazywany do zastąpionego elementu Metoda onDraw(). Metoda super.onDraw() jest wywoływana przed funkcją . Należy wywołać metodę klasy nadrzędnej. W tym przypadku wywołaj go na końcu po i narysujesz linie, które chcesz uwzględnić.

  4. Komponent niestandardowy

    Masz już komponent niestandardowy, ale jak go wykorzystać? W przykładowym formacie NotePad funkcja jest używany bezpośrednio z układu deklaratywnego, więc spójrz na note_editor.xml w: res/layout. folder:

    <view xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.example.android.notepad.NoteEditor$LinedEditText"
        android:id="@+id/note"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:padding="5dp"
        android:scrollbars="vertical"
        android:fadingEdge="vertical"
        android:gravity="top"
        android:textSize="22sp"
        android:capitalize="sentences"
    />
    

    Komponent niestandardowy jest tworzony w pliku XML jako widok ogólny, a klasa została określona. korzystając z pełnego pakietu. Do zdefiniowanej przez Ciebie klasy wewnętrznej odwołuje się funkcja Zapis NoteEditor$LinedEditText, który jest standardowym sposobem określania obiektu wewnętrznego w języku programowania Java.

    Jeśli komponent widoku niestandardowego nie jest zdefiniowany jako klasa wewnętrzna, możesz zadeklarować widok z nazwą elementu XML i wykluczyć atrybut class. Dla: przykład:

    <com.example.android.notepad.LinedEditText
      id="@+id/note"
      ... />
    

    Zwróć uwagę, że klasa LinedEditText jest teraz oddzielnym plikiem klas. Gdy jest zagnieżdżona w klasie NoteEditor, ta metoda nie działa.

    Pozostałe atrybuty i parametry w definicji to te, które są przekazywane do parametru niestandardowego do konstruktora komponentów, a potem do konstruktora EditText, więc to te same parametry, co w widoku EditText. Możesz dodać za pomocą własnych parametrów.

Tworzenie komponentów niestandardowych jest tak skomplikowane, jak to konieczne.

Bardziej zaawansowany komponent może zastąpić jeszcze więcej metod on i wprowadzić jego własnych metod pomocniczych, zasadniczo dostosowując właściwości i działanie. Jedynym ograniczeniem jest wyobraźnię i do czego potrzebny jest komponent.