Ta strona używa ciasteczek (cookies), dzięki którym nasz serwis może działać lepiej. Rozumiem
Jakub Pawlak / 04.09.2018

Optymalizacja widoków w NativeScript z Angularem

Swoją przygodę z NativeScriptem zacząłem od tworzenia widoków zgodnie z projektem graficznym. Początki nie były szczególnie trudne dzięki wcześniejszym doświadczeniom z natywnymi aplikacjami mobilnymi na Androida miałem już wyobrażenie o tym, jak wygląda struktura Androidowego XMLa. Głównym problemem okazała się początkowo niepełna i czasami nieaktualna dokumentacja oraz próba przeniesienia webowego HTMLa na NativeScriptowe widoki.


Zbyt swobodne podejście do stosowania natywnych elementów niczym HTMLowych divów sprawiło, że pierwsza aplikacja, nad którą pracowałem szybko zaczęła łapać zadyszkę. Mimo dużej wydajności obecnych telefonów, słabsze urządzenia mogą radzić sobie gorzej z generowaniem skomplikowanej struktury widoków w aplikacji mobilnej.


Widoki w NativeScript

W NativeScriptcie mamy do wyboru 6 predefiniowanych układów:

  • AbsoluteLayout - pozwalający na ustawianie widoków po ich współrzędnych. W takim kontenerze możemy nakładać widoki na siebie i precyzyjnie określać ich lokalizację. Kłopot może stanowić responsywność - układ naszego widoku na różnych rozmiarach ekranów.

  • DockLayout - bardzo przydatny kontener, jeśli chcemy utrzymać widok przypięty do którejś części ekranu, np. przycisk zawsze na samym dole widoku.

  • FlexboxLayout - odpowiednik webowego flexboxa - bardzo elastyczny kontener, dający dużo możliwości.

  • GridLayout - układ, w którym możemy ustawić prawie wszystko. Pozwala na ułożenie dowolnie skomplikowanego widoku oraz nakładanie widoków na siebie. Podstawowy kontener w naszej codziennej pracy.

  • StackLayout - widoki w tym kontenerze są ustawiane pod sobą lub obok siebie, w zależności od orientacji jaką ustawimy

  • WrapLayout - jeśli mamy do ułożenia widoki, które będą płynnie przechodziły do kolejnych wierszy lub kolumn w zależności od rozmiarów ekranu, możemy wykorzystać do tego właśnie ten układ.


Dokumentacja NativeScripta dobrze opisuje każdy układ wraz z jego atrybutami, dlatego nie będę opowiadał o każdym z osobna. Możesz znaleźć ją tutaj. Zamiast tego wolę skupić się na jednym, który nadaje się prawie do wszystkiego!


Widok do zadań specjalnych

GridLayout, bo o nim mowa, pozwala ograniczyć do minimum ilość generowanych przez aplikację warstw. Każdy dodatkowy kontener to kolejna warstwa do wyświetlenia. Strukturę warstw aplikacji można sprawdzić np. w Xcode.


xcode_unoptimized
 

Tak wygląda niezoptymalizowany widok. Każdy układ generuje kolejny kontener UIView.



 

Możemy ograniczyć ilość tych widoków wykorzystując GridLayout.

 

W przypadku prostego interfejsu nie będzie to miało dużego znaczenia, ale w przypadku długiej listy skomplikowanych elementów optymalizacja układu może okazać się konieczna.

Zbudujemy prosty interfejs z widokiem karty w NativeScript Playground, a następnie zoptymalizujemy jego strukturę.

 

dock_latout_optimized

 

Gotowy projekt można znaleźć na githubie.

 

Podstawowy układ aplikacji

Otwieramy nowy projekt {N} + Angular na stronie Nativescript Playground. Aby zainstalować aplikację na telefonie wystarczy kliknąć Preview i zeskanować kod QR telefonem przez aplikację Playground.


New playground
 

W lewym panelu widzimy strukturę plików naszego projektu. Poniżej znajdują się komponenty, które możemy przenosić do kodu metodą drag&drop. Podstawowym widokiem aplikacji jest app.component.html, który zawiera <‌page-router-outlet>. Jest to tzw rama dla wszystkich ekranów aplikacji po których możemy nawigować i które definiuje się w tak samo jak w Angularowych aplikacjach, za pomocą Routera. Szczegółowe informacje o nawigacji i strukturze aplikacji znajdują się tutaj.

Głównym ekranem aplikacji, na który jesteśmy przekierowywani automatycznie jest home.component. Zawiera 2 główne elementy: ActionBar wyświetlany zawsze na górze aplikacji oraz GridLayout, który jest głównym kontenerem dla naszych widoków.

Ważne: Jeżeli komponent jest obiektem klasy Page może zawierać tylko jeden ActionBar i tylko jeden główny komponent. W przeciwnym wypadku NativeScript może wyświetlić błąd.

Nasza aplikacja posiada kartę oraz przycisk na samym dole ekranu. Do takiego układu idealny będzie DockLayout. Zmieńmy podstawowy GridLayout na DockLayout dodając do niego klasę page i wstawmy do niego Label i Button. Należy pamiętać, że NativeScript nie obsługuje tzw. samozamykających się tagów (np. <‌Label text="Label"/>), czyli każdy tag powinien mieć zamknięcie. W innym wypadku wystąpi błąd szablonu.


dock_layout

Taki układ jednak nie wystarczy, aby przycisk znalazł się na samym dole. Do Labela i Buttona musimy dodać atrybut dock.


dock_layout_bottom

Nadal nie uzyskaliśmy pożądanego efektu. Dla ułatwienia, możemy dodać do elementów atrybuty backgroundColor.

 

dock_layout_bg

 

Kod powienien w tym momencie wyglądać tak jak tu. Widać, że Button jest rozciągnięty na całą wysokość ekranu. Wystarczy teraz ustawić atrybut stretchLastChild w DockLayout na false i uzyskamy przycisk przesunięty na sam dół ekranu.

 

dock_layout_stretch

 

Aktualny widok struktury aplikacji można zobaczyć tutaj.

Widok z web’a wzięty

Stwórzmy teraz widok karty zgodnie ze strukturą sugerowaną przez popularną front-endową bibliotekę - Bootstrapa.


dock_layout_bootstrap

 

Zamiast Label’a pojawił się StackLayout z CSSową klasą card. Zawiera on 3 kolejne kontenery: card-header, hr-light i card-body. Klasa hr-light, to pomocnicza klasa z głównego motywu NativeScripte’a, która jest importowana w pliku app.css. Nagłówek karty to GridLayout z dwoma kolumnami i jednym wierszem. Atrybuty “columns” i “rows” przyjmują listę elementów “*” lub “auto”. Gwiazdka oznacza, że kolumna o tym indeksie przyjmie maksymalną szerokość, a “auto” minimalną w jakiej zmieści się jej zawartość. Pojawił się także obrazek, który dodałem w folderze images. Warto zwrócić uwagę na fragment:


W NativeScript’cie nie możemy ostylować fragmentu tekstu wprost. Służy do tego element <‌FormattedString>, którego stosowanie omówię w innym poście. Na potrzeby tego tutoriala wykorzystamy StackLayout z poziomą orientacją z dwoma oddzielnymi elementami typu Label.

Dodajmy teraz trochę CSSów w home.component.css


Aplikacja powinna teraz wyglądać tak:

 

dock_latout_optimized

 

Kompletny kod do aktualnej wersji można sprawdzić tutaj.

Optymalizacja układu do siatki

Wygląd jest zgodny z projektem, jednak jego struktura jest przesadnie skomplikowana, co negatywnie wpłynie na wydajność aplikacji przy większej ilości elementów. Do stworzenia karty, zamiast kilku zagnieżdżonych kontenerów, wystarczy 1 GridLayout. Podczas tworzenia widoków nie trzeba od razu przejmować się ich ‘płaską’ strukturą. Jeśli komponent stanowi zamkniętą całość, od razu możemy przemyśleć jak umieścić go w siatce, jednak aby maksymalnie zoptymalizować strukturę, musimy znać ostateczny układ. Omawiany widok karty składa się z 3 kolumn i 4 wierszy, przy czym środkowa kolumna, zawierająca Label z datą, może zajmować maksymalną szerokość, tak aby obrazek znalazł się po prawej stronie. Następnie dodajemy do naszych elementów odpowiednie indeksy kolumn i wierszy, pamiętając o tym, że pierwszy element zawsze posiada indeks = 0. Ostateczny układ karty będzie wyglądał następująco:


Więcej informacji o tym w jaki sposób można jeszcze efektywniej optymalizować aplikację tworzoną w NativeScript z Angularem można znaleźć na blogu {N} tutaj. Korzystanie z GridLayout może być kłopotliwe, gdy nie znamy ostatecznej ilości wierszy i kolumn, np. gdy pobieramy dynamicznie dane z bazy danych. Musimy wtedy powiązać atrybuty siatki ze zmienną, którą utworzymy w logice naszego widoku. Chcecie dowiedzieć się jak to zrobić? Dajcie znać w komentarzach!

 

Udostępnij:
Jakub Pawlak
Programista aplikacji mobilnych

Programista mobile i front-end. Po godzinach saksofonista i kitesurfer.

Stwórzmy coś niesamowitego, poznaj nas i zatrudnij.

Wyceń projekt