Rozmowa o pracę jako programista Flutter – pytania i odpowiedzi

Wybierasz się (pewnie wirtualnie, ale jednak…) na rozmową kwalifikacyjną na stanowisko Flutter Developera? Może jesteś dopiero na początku ścieżki programisty i zastanawiasz się czy Flutter to rozwiązanie dobre dla Ciebie? Chcesz poznać podstawowe nazewnictwo związane z Flutterem? Świetnie! W tym wpisie (który będzie cały czas aktualizowany) postaram się zawrzeć wszystkie najważniejsze informacje na temat Fluttera. Jeśli coś jest niezrozumiałe, jeśli Twoim zdaniem coś można lepiej napisać, jeśli coś powinienem poprawić albo po prostu brakuje tutaj czegość – daj mi proszę znać w komentarzach!

Czym jest Flutter?
Flutter to rozwiązanie (technologia) open-source stworzona przez Google w 2018 roku. Flutter to NIE JEST język programowania. To zestaw narzędzi pozwalający na tworzenie aplikacji dla Androida, iOS’a, Linuxa, Maca, Windows, a już za chwilę również dla web za pomocą jednego kodu (w dużym uproszczeniu). Aplikacje flutterowe korzystają z języka Dart.

Czym jest Dart?
Dart to język programowania, który został stworzony przez firmę Google w 2011 roku. Jest to język zorientowany obiektowo, oparty na klasach wykorzystujący składnię język C. Pierwotnie język ten wykorzystywany był przede wszystkim do rozwiązań webowych, jednak to dzięki Flutterowi Dart stał się znany (i lubiany ;).

Jakie są zalety Fluttera?

  • Doskonały sposób na rozwój cross-platformowych aplikacji
  • Szybki development
  • Wspaniała społeczność
  • Świetna dokumentacja
  • Hot reload
  • Dostępność pakietów
  • Natywny look and feel aplikacji zarówno w iOS jak i w Android

Konwencje nazewnictwa wykorzystywane we Flutterze

  • UpperCamelCase – wykorzystywany przy tworzeniu klas, typów enum
  • lowerCamelCase – stałe, metody i identyfikatory
  • lower_case – nazwy bibliotek, pakietów, katalogów i plików

Czy jest plik pubspec.yaml i jakie jest jego zadanie?
Plik pubspec.yaml to plik, w którym definijuemy wszystkie zależności oraz tzw. assety (pliki zewnętrzne, grafiki, fonty) wykorzystywane w projekcie. W tym pliku definiujemy również opis i nazwę dla projektu.

Jakie są podstawowe komendy wykorzystywane przy developmencie we Flutterze?
flutter doctor – komenda sprawdzająca stan zainstalowanego środowiska. Wynikiem działania tej komendy jest informacja na temat ew. problemów, braków oraz zadań do wykonania celem naprawy stanu.

flutter clean – komenda, która czyści cache naszego projektu.

flutter upgrade – komenda aktualizująca zainstalowane środowisko Fluttera do najnowszej wersji w aktualnie użytkowanym kanale. Aby sprawdzić jaki kanał jest aktualnie wykorzystywany używamy komendy flutter channel. Zmiana kanał możliwa jest za pomocą komendy: flutter channel <channel-name> np. flutter channel dev.

flutter pub get – komenda pobierająca wszystkie zależności zdefiniowane w pliku pubspec.yaml. Jeśli do pliku zostały dopisane jakieś assety czy nowe pakiety wykonanie tej komendy jest niezbędne aby zmiany były widoczne w projekcie.

flutter pub upgrade – komenda pobiera wszystkie wylistowanie w pliku pubspec.yaml zależności w najnowszej dostępnej wersji.

Czym są flutterowe widgety Jakie mamy typy widgetów ?
We Flutterze wszystko jest widgetem. Widget to podstawowy element interfejsu użytkownika. Wyróżniamy dwa typy widgetów: StatelessWidget oraz StatefulWidget.

Widgety StatelessWidget nie wymagają stanu, ich build method jest uruchomiony tylko jeden raz i nie mogą zmienić później swojego stanu podczas działania aplikacji. Jeśli chcemy odświeżyć taki widget musimy wywołać jego nową instancję.

Widgety StatefulWidget posiadają swój, zmienny, stan. Takie widgety mogą być tworzone dowolną ilość razy w ciągu cyklu życia aplikacji (gdy aplikacja jest uruchomiona).

Co to jest stan i co robi setState() ?
Stan to zbiór zmiennych, wartości czy ustawień widgetu. Wszystko co możemy zmienić (np. tekst, kolor) może być częścią danego stanu.
setState() to jeden ze sposobów aktualizacji stanu. Za pomocą setState() możemy odświeżyć i przebudować screen aktualizując wszystkie potrzebne informacje.

Jaki jest cykl życia (lifecycle) widgetu StatefulWidget?

  • createState()
  • initState()
  • didChangeDependencies()
  • build()
  • didUpdateWidget()
  • deactivate()
  • dispose()

Jaka jest różnica mięcy hot reload, hot restart i pełnym restartem?
Flutterowy Hot reload to bardzo przyjemny sposób na szybkie zbudowanie aplikacji, poprawkę bugów czy sprawdzenie nowych rozwiązań. Hot reload „wstrzykuje” zaktualizowany kod do wirtualnej maszyny (VM) Darta, a framework Fluttera po zaktualizowaniu nowch funkcji czy pól automatycznie przebudowuje drzewo widgetów pozwalając szybko zobaczyć efekty pracy.

Hot restart aktualizuje zmiany w kodzie, przebudowuje wszystkie widgety restartując aplikację tracąc tym samym jej poprzedni stan. Zabiera zdecydowanie więcej czasu niż hot reload.

Full restart to pełny restart aplikacji. Rekompiluje cały kod, trwa najdłużej ale zapewnia, że wszystkie zmiany wprowadzone w aplikacji będą widoczne.

Czym jest klasa Future?
Future reprezentuje potencjalny wynik, wartośc lub błąd, które może się pojawić/być dostępnym za jakiś czas. Otrzymując Future’a możemy stwirzyć callbacka, który obsłuży otrzymany wynik (lub error). Future jest wynikiem operacji asnychronicznej (asynchronous operation). Future może mieć dwa stany: uncompleted lub completed.

Czym sie różni programowanie synchroniczne od asynchronicznego ?
W synchronicznym programowaniu kod wykonywany jest linkija po linijce. Kolejne synchroniczne operacje wykonyane są dopiero w momencie gdy poprzednie bloki zostały wykonane. W programowaniu asynchronicznym pozwalamy aplikacji na działanie niezależnie od wyniku poszczególnych operacji.

Async i await – do czego służą ?
Są to słowa dzięki którym zadeklarujemy funkcje asynchroniczne oraz ich wyniki. Słowo kluczowe async wykorzystujemy do zaznaczenia, iż dana funkcja jest asynchroniczna. Await wykorzystywany jest do otrzymania rezultatu asynchronicznego wyrażenia. Await działa jedynie w funkcjach oznaczonych jako asynchroniczne za pomocą async.

Gdzie szukać pracy jako Flutter Developer?
Flutter jest ciągle stosunkowo nowym rozwiązaniem, jednak bardzo szybko zyskuje na popularności. Jeszcze rok temu próżno było szukać na polskim rynku ofert pracy związanych z tą technologią, a dziś sytuacja zaczyna wyglądać już zupełni inaczej. Flutter developerzy zaczynają być poszukiwani nie tylko przez startupy, ale również w dużych firmach powstają zespoły mające za zadanie zająć się tym cross-platformowym rozwiązaniem. Oto kilka linków od których powinieneś zacząć szukając pracy jako Flutter Developer: JustJoin, Bulldogjob, Pracuj.pl, Nofluffjobs, Linkedin.

Widget TextField()

Widget TexField wykorzystywany jest we Flutterze do odbierania danych tekstowych od użytkownika. To klasyczne, proste pole tekstowe wykorzystujemy za każdym razem gdy tworzymy ekran logowania czy najprostszy formularz. Aby stworzyć TextField’a używamy następującego kodu:

TextField()

dzięki czemu otrzymujemy widget, który wygląda dokładnie tak:

Pole TextField

Puste pole tekstowe to nic innego jak miejsce na tekst użytkownika. Domyślnie (właściwość autofocus: false) pole to jest nieaktywne, a dokładniej nazywając rzecz po imieniu pole jest „bez focusa”. Gdy na nie klikniemy focus staje się aktywny, na ekranie wyświetlana jest klawiatura, a użytkownik może zacząć wpisywać tekst. Możemy oczywiście wymusić, aby po załadowaniu ekranu dane pole tekstowe było „sfocusowane” i gotowe do przyjęcia tekstu poprzez zmianę właściwości autofocus na true:

autofocus: true

Pobieranie wartości z pola tekstowego

Nie sposób nie zauważyć, że w przypadku widgetów nie mamy do czynienia z ich ID, w związku z czym nasuwa się pytanie – w jaki sposób odebrać dane od użytkownika? Jak pobrać login i wpisane hasło, aby móc je później wykorzystać jako zmienną ? Otóż można tego dokonać w następujący sposób:

String zmiennaTekstowa = "";

TextField(
  onChanged: (text) {
    zmiennaTekstowa = text;
  },
)

Wykorzystując zdarzenie onChanged TextField’a pobieramy wpisany do naszego pola tekst (text) przy każdej zmianie która nastąpi w polu tekstowym i następnie przypisujemy ją do naszej zmiennej zmiennaTekstowa typu String. Działa tutaj tzw „callback”.

onChanged: (text) {
    zmiennaTekstowa = text;
  },

Drugim sposobem pracy z TextField() jest stworzenie kontrolera TextEditingController, który będzie podpięty pod nasze pole tekstowe i będzie nam pozwalał nasłuchiwać zmiany w tym polu. Aby tego dokonać tworzymy kontroler i podpinamy go jako właściwość w polu tekstowym:

TextEditingController controllerTextField = TextEditingController();

TextField(
  controller: controllerTextField,
)

Teraz, aby zacząć nasłuchiwać zmian w naszym polu tworzymy tzw.: listnera:

controllerTexField.addListner((){
       print(controllerTexField.text); //drukujemy w konsoli zawartość pola
})

Zmiana wyglądu pola tekstowego

W przypadku gdy budujemy aplikację we Flutterze opartą o Material App za wygląd pola tekstowego odpowiada właściwość InputDecoration. Możliwości są ogromne i obejmują nie tylko zmianę koloru, czcionki, kształtu czy wybór ramki, ale również możliwość umieszczenia podpowiedzi do pola czy ikonki w polu tekstowym.

TextField(
                  decoration: InputDecoration(
                    hintText: 'To jest podpowiedź',
                    hintStyle: TextStyle(
                      color: Colors.red,
                      fontStyle: FontStyle.italic,
                      fontSize: 20,
                    ),
                  ),
                ),

Ikonka w polu tekstowym

Pole tekstowe można również wyposażyć w ikonkę, można tego dokonać w bardzo prosty sposób wybierając odpowiednią pozycję z zasobu np. Icons. Następujący kod:

TextField(
                  decoration: InputDecoration(
                    icon: Icon(Icons.shopping_cart),
                  ),
                ),

pozwoli nam na uzyskane następującego efektu:

Pole tekstowe z ikonką

Pole tekstowe z ramką

Wygląd pola tekstowego możemy edytować na wiele sposobów, jednym z nich jest modyfikacja wyglądu ramki. Mamy możliwość zmiany kształtu, koloru, grubości ramki zarówno pola bez focusa jak i pola klikniętego. Domyślnie w przypadku aplikacji opartej o Material pole tekstowe nie posiada żadnej ramki, możemy to bardzo szybko zmienić za pomocą następującego kodu:

                 TextField(
                          decoration: InputDecoration(
                            enabledBorder: OutlineInputBorder(
                              borderSide:
                                  BorderSide(color: Colors.red, width: 1.0),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderSide:
                                  BorderSide(color: Colors.orange, width: 5.0),
                            ),
                          ),
                        ),

enabledBorder odpowiada za wygląd ramki domyślnie załadowanego pola tekstowego, a właściwość focusedBorder zmienia wygląd pola w momencie aktywności. Efektem działania powyższego kodu będzie pole z czerwoną ramką w szerokości 1.0px, które w momencie aktywności zmieni się na ramkę o szerokości 5.0px w kolorze pomarańczowym (tak wiem, świetnie połączenie kolorów… 😉 :

Border możemy oczywiście estetycznie zaokrąglić otrzymując efektowne pole, którego nie powstydziłby się żaden projektant:

BorderRadius w akcji
                        decoration: InputDecoration(
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(25.0),
                            ),
                          ),

Wybór klawiatury dla pola tekstowego

Często zdarza się, że przygotowują poszczególne pola typu TextField np. programując formularz rejestracji chcemy ułatwić użytkownikowi interakcję z aplikacją. Jednym ze sposobów dokonania tego jest usunięcie zbędnych pól klawiatury przy wprowadzaniu numeru telefonu czy kwoty (w takim przypadku wiemy, że user powinien wpisać cyfry). Nasze pole TextField może mieć narzuconą klawiaturę alfanumeryczną (domyślna), numeryczną, telefoniczną etc. za pomocą właściwości keyboardType.

keyboardType: TextInputType.emailAddress,
//dla pola e-mail

keyboardType: TextInputType.number,
//klawiatura numeryczna

keyboardType: TextInputType.multiline,
//klawiatura z przyciskiem enter i przejście do następnej linii

keyboardType: TextInputType.phone
//klawiatura telefoniczna

Pole typu hidden dla haseł

Pole tekstowe typu hidden wykorzystywane jest za każdym razem gdy chcemy, aby użytkownik wprowadził hasło czy to przy rejestracji czy przy logowaniu do aplikacji. Aby zabezpieczyć pole tekstowe i zamiast wpisywanego tekstu zobaczyć w nim czarne kropki wystarczy zmienić domyślna wartość właściwości obscureText z false na true:

obscureText: true,

Stylowanie tekstu i kolor tła

Wygląd pola tekstowego możemy również zmienić za pomocą właściwości Style, która pozwala nam na wybór kroju czcionki, wielkości i np. koloru.

                     style: TextStyle(
                            color: Colors.red,
                            fontSize: 40,
                            fontWeight: FontWeight.bold,
                          ),

W przypadku chęci zmiany koloru tła musimy sięgnąć do wspomnianej już wcześniej właściwości decoration i InputDecoration gdzie wprowadzamy „kolor wypełnienia” oraz wypełniamy pole zmieniając właściwość filled na true:

decoration: InputDecoration(fillColor: Colors.yellow, filled: true),

Owocem powyższego kodu będzie „piękne” żółte pole tekstowe z jeszcze piękniejszym fontem w kolorze czerwonym:

Pozostałe właściwości TextField() które warto znać

textAlign – ustawia kursor we wskazanym miejscu pola tekstowego. Tekst w polu może być wyśrodkowany, wyjustowany, ustawiony po prawej lub lewej stronie pola lub w jego dowolnym miejscu.

TextField(
	  textAlign: TextAlign.center,
	  ),
Wyśrodkowany kursor w polu tekstowym

maxLength – właściwość ta przyda się wszędzie tam, gdzie musimy ograniczyć długość wprowadzanego tekstu, wszelkie maści pola telefon czy np. kod pocztowy powinny być ograniczone

maxLength: 4,

showCursor – za pomocą tej właściwości możemy ukryć w polu tekstowym kursor, nie będzie on widoczny dla użytkownika

showCursor: false
//ukrywa kursor w polu tekstowym

textCapitalization – możemy tak ustawić właściwości pola tekstowego aby odpowiednie wyrazy, litery, lub cały tekst był pisany dużymi literami.

TextField(
 textCapitalization: TextCapitalization.sentences,
),
//tradycyjne ustawienie, w którym zdania rozpoczynają się z wielkiej litery

TextField(
 textCapitalization: TextCapitalization.characters,
),
//wszystkie litery w polu tekstowym pisane jako wielkie

TextField(
 textCapitalization: TextCapitalization.words,
),
//każdy wyraz rozpoczynał się będzie wielką literą

Pole aktywne i nieaktywne

Czasem może się zdarzyć, że nasze pole tekstowe nie powinno być aktywne aż do jakiegoś momentu (np. do wypełnienia wcześniejszego pola lub wyboru jakieś opcji). W takim wypadku możemy uaktywniać lub w razie potrzeby dezaktywować pole za pomocą następującego kodu:

enabled:true,
//ustawienie domyślne, pole jest aktywne

enabled:false
//ustawienie sprawia, że pole tekstowe jest nieaktywne

 

Źródła i polecane linki:

 

Hello World!

Cześć. Zakochałem się we Flutterze. Nasza znajomość rozkwitła podczas Koronawirusowej kwarantanny więc postanowiłem pójść za ciosem. Podobno dobrym sposobem na naukę i utrwalenie wiedzy jest dzielenie się nią. Więc jestem. Flutterowy Junior. Na tym blogu chciałbym opisać moje postępy w nauce programowania i jednocześnie stworzyć elektroniczny notatnik do którego będę mógł wracać oraz którym będę się mógł posiłkować w razie konieczności. Wiem, że droga przed którą jestem będzie długa i wyboista, ale jestem gotów. Jeśli również Ciebie zainteresował Flutter i tworzenie aplikacji mobilnych to być może przydadzą Ci się również moje notatki ?. Zapraszam do lektury, komentowania i wymiany wiedzy!