Flutter - Szybki przewodnik

Ogólnie rzecz biorąc, tworzenie aplikacji mobilnej jest złożonym i wymagającym zadaniem. Dostępnych jest wiele frameworków do tworzenia aplikacji mobilnych. Android zapewnia natywną strukturę opartą na języku Java, a iOS zapewnia natywną strukturę opartą na języku Objective-C / Swift.

Jednak aby opracować aplikację obsługującą oba systemy operacyjne, musimy kodować w dwóch różnych językach przy użyciu dwóch różnych frameworków. Aby pomóc przezwyciężyć tę złożoność, istnieją platformy mobilne obsługujące oba systemy operacyjne. Struktury te obejmują zarówno proste, hybrydowe ramy aplikacji mobilnych oparte na języku HTML (które wykorzystują HTML dla interfejsu użytkownika i JavaScript do logiki aplikacji), jak i złożone ramy specyficzne dla języka (które wykonują ciężkie prace związane z konwersją kodu do kodu natywnego). Niezależnie od swojej prostoty i złożoności, te frameworki zawsze mają wiele wad, a jedną z głównych wad jest ich powolne działanie.

W tym scenariuszu Flutter - prosta i wydajna platforma oparta na języku Dart, zapewnia wysoką wydajność, renderując interfejs użytkownika bezpośrednio w kanwie systemu operacyjnego, a nie przez natywną strukturę.

Flutter oferuje również wiele gotowych do użycia widżetów (UI) do tworzenia nowoczesnych aplikacji. Te widżety są zoptymalizowane pod kątem środowiska mobilnego, a projektowanie aplikacji przy użyciu widżetów jest tak proste, jak projektowanie HTML.

Mówiąc konkretnie, aplikacja Flutter sama w sobie jest widżetem. Widżety Flutter obsługują również animacje i gesty. Logika aplikacji oparta jest na programowaniu reaktywnym. Widget może opcjonalnie mieć stan. Zmieniając stan widżetu, Flutter automatycznie (programowanie reaktywne) porówna stan widżetu (stary i nowy) i wyrenderuje widżet z tylko niezbędnymi zmianami zamiast ponownego renderowania całego widżetu.

W następnych rozdziałach omówimy całą architekturę.

Funkcje Fluttera

Framework Flutter oferuje programistom następujące funkcje -

  • Nowoczesny i reaktywny framework.

  • Używa języka programowania Dart i jest bardzo łatwy do nauczenia.

  • Szybki rozwój.

  • Piękne i płynne interfejsy użytkownika.

  • Ogromny katalog widżetów.

  • Działa z tym samym interfejsem użytkownika na wielu platformach.

  • Aplikacja o wysokiej wydajności.

Zalety Fluttera

Flutter jest wyposażony w piękne i konfigurowalne widżety zapewniające wysoką wydajność i wyjątkową aplikację mobilną. Spełnia wszystkie niestandardowe potrzeby i wymagania. Poza tym Flutter oferuje o wiele więcej zalet, jak wspomniano poniżej -

  • Dart posiada duże repozytorium pakietów oprogramowania, które pozwala rozszerzyć możliwości Twojej aplikacji.

  • Programiści muszą napisać tylko jedną bazę kodu dla obu aplikacji (na platformach Android i iOS). W przyszłości Flutter może zostać rozszerzony na inną platformę.

  • Flutter wymaga mniej testów. Ze względu na jego pojedynczy kod wystarczy, że napiszemy testy automatyczne raz dla obu platform.

  • Prostota Fluttera sprawia, że ​​jest dobrym kandydatem do szybkiego rozwoju. Jego możliwości dostosowywania i rozszerzania sprawiają, że jest jeszcze potężniejszy.

  • Dzięki Flutter programiści mają pełną kontrolę nad widżetami i ich układem.

  • Flutter oferuje świetne narzędzia programistyczne z niesamowitym ponownym ładowaniem.

Wady Fluttera

Pomimo wielu zalet trzepotanie ma w sobie następujące wady -

  • Ponieważ jest napisany w języku Dart, programista musi nauczyć się nowego języka (choć jest to łatwe do nauczenia).

  • Nowoczesny framework próbuje oddzielić logikę i interfejs użytkownika tak bardzo, jak to możliwe, ale we Flutterze interfejs użytkownika i logika są mieszane. Możemy temu zaradzić, stosując inteligentne kodowanie i używając modułu wysokiego poziomu do oddzielenia interfejsu użytkownika i logiki.

  • Flutter to kolejny framework do tworzenia aplikacji mobilnych. Deweloperzy mają trudności z wyborem odpowiednich narzędzi programistycznych w bardzo zaludnionym segmencie.

Ten rozdział szczegółowo poprowadzi Cię przez instalację Fluttera na Twoim komputerze lokalnym.

Instalacja w systemie Windows

W tej sekcji zobaczmy, jak zainstalować Flutter SDK i jego wymagania w systemie Windows.

Step 1 - Idź do adresu URL,https://flutter.dev/docs/get-started/install/windowsi pobierz najnowszy Flutter SDK. Od kwietnia 2019 roku wersja to 1.2.1, a plik to flutter_windows_v1.2.1-stable.zip.

Step 2 - Rozpakuj archiwum zip w folderze, powiedz C: \ flutter \

Step 3 - Zaktualizuj ścieżkę systemową, aby zawierała katalog bin flutter.

Step 4 - Flutter zapewnia narzędzie, lekarz flutter, który sprawdza, czy wszystkie wymagania rozwoju trzepotania są spełnione.

flutter doctor

Step 5 - Uruchomienie powyższego polecenia przeanalizuje system i pokaże raport, jak pokazano poniżej -

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version
10.0.17134.706], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version
28.0.3)
[√] Android Studio (version 3.2)
[√] VS Code, 64-bit edition (version 1.29.1)
[!] Connected device
! No devices available
! Doctor found issues in 1 category.

Raport mówi, że wszystkie narzędzia programistyczne są dostępne, ale urządzenie nie jest podłączone. Możemy to naprawić, podłączając urządzenie z Androidem przez USB lub uruchamiając emulator Androida.

Step 6 - Zainstaluj najnowszy Android SDK, jeśli zgłosi to lekarz flutter

Step 7 - Zainstaluj najnowszą wersję Android Studio, jeśli zgłosi to lekarz flutter

Step 8 - Uruchom emulator Androida lub podłącz prawdziwe urządzenie z Androidem do systemu.

Step 9- Zainstaluj wtyczkę Flutter i Dart dla Android Studio. Zapewnia szablon startowy do tworzenia nowej aplikacji Flutter, opcję uruchamiania i debugowania aplikacji Flutter w samym studiu Android itp.,

  • Otwórz Android Studio.

  • Kliknij Plik → Ustawienia → Wtyczki.

  • Wybierz wtyczkę Flutter i kliknij Zainstaluj.

  • Kliknij Tak, gdy pojawi się monit o zainstalowanie wtyczki Dart.

  • Uruchom ponownie Android Studio.

Instalacja w systemie MacOS

Aby zainstalować Flutter na MacOS, będziesz musiał wykonać następujące kroki -

Step 1 - Idź do adresu URL,https://flutter.dev/docs/get-started/install/macosi pobierz najnowszy Flutter SDK. Od kwietnia 2019 r. Wersja to 1.2.1, a plik to flutter_macos_v1.2.1- stabilny.zip.

Step 2 - Rozpakuj archiwum zip w folderze, powiedz / path / to / flutter

Step 3 - Zaktualizuj ścieżkę systemową, aby zawierała katalog bin flutter (w pliku ~ / .bashrc).

> export PATH = "$PATH:/path/to/flutter/bin"

Step 4 - Włącz zaktualizowaną ścieżkę w bieżącej sesji za pomocą poniższego polecenia, a następnie również ją zweryfikuj.

source ~/.bashrc
source $HOME/.bash_profile
echo $PATH

Flutter zapewnia narzędzie, lekarz flutter, który sprawdza, czy wszystkie wymagania rozwoju trzepotania są spełnione. Jest podobny do odpowiednika w systemie Windows.

Step 5 - Zainstaluj najnowszy kod XCode, jeśli zostanie zgłoszony przez lekarza flutter

Step 6 - Zainstaluj najnowszy Android SDK, jeśli zgłosi to lekarz

Step 7 - Zainstaluj najnowszą wersję Android Studio, jeśli zostanie zgłoszona przez lekarza flutter

Step 8 - Uruchom emulator Androida lub podłącz prawdziwe urządzenie z Androidem do systemu, aby opracować aplikację na Androida.

Step 9 - Otwórz symulator iOS lub podłącz do systemu prawdziwe urządzenie iPhone, aby stworzyć aplikację iOS.

Step 10- Zainstaluj wtyczkę Flutter i Dart dla Android Studio. Zapewnia szablon startowy do stworzenia nowej aplikacji Flutter, opcję uruchamiania i debugowania aplikacji Flutter w samym studiu Android itp.,

  • Otwórz Android Studio

  • Kliknij Preferences → Plugins

  • Wybierz wtyczkę Flutter i kliknij Zainstaluj

  • Kliknij Tak, gdy pojawi się monit o zainstalowanie wtyczki Dart.

  • Uruchom ponownie Android Studio.

W tym rozdziale stwórzmy prostą aplikację Flutter , aby zrozumieć podstawy tworzenia aplikacji flutter w Android Studio.

Step 1 - Otwórz Android Studio

Step 2- Utwórz projekt Flutter. W tym celu kliknijFile → New → New Flutter Project

Step 3- Wybierz aplikację Flutter. W tym celu wybierzFlutter Application i kliknij Next.

Step 4 - Skonfiguruj aplikację jak poniżej i kliknij Next.

  • Nazwa Projektu: hello_app

  • Ścieżka Flutter SDK: <path_to_flutter_sdk>

  • Lokalizacja projektu: <path_to_project_folder>

  • Opis: Flutter based hello world application

Step 5 - Konfiguruj projekt.

Ustaw domenę firmy jako flutterapp.tutorialspoint.com i kliknij Finish.

Step 6 - Wpisz domenę firmy.

Android Studio tworzy w pełni działającą aplikację flutter o minimalnej funkcjonalności. Sprawdźmy strukturę aplikacji, a następnie zmień kod, aby wykonać nasze zadanie.

Struktura aplikacji i jej przeznaczenie są następujące -

Tutaj wyjaśniono różne elementy struktury aplikacji -

  • android - Automatycznie generowany kod źródłowy do tworzenia aplikacji na Androida

  • ios - Automatycznie wygenerowany kod źródłowy do tworzenia aplikacji na iOS

  • lib - Główny folder zawierający kod Dart napisany przy użyciu frameworka flutter

  • ib/main.dart - Punkt wejścia do aplikacji Flutter

  • test - Folder zawierający kod Dart do testowania aplikacji flutter

  • test/widget_test.dart - Przykładowy kod

  • .gitignore - Plik kontroli wersji Git

  • .metadata - automatycznie generowane przez narzędzia flutter

  • .packages - automatycznie generowane w celu śledzenia pakietów flutter

  • .iml - plik projektu używany przez studio Android

  • pubspec.yaml - Używany przez Pub, Menedżer pakietów Flutter

  • pubspec.lock - Automatycznie generowane przez menedżera pakietów Flutter, Pub

  • README.md - Plik opisu projektu zapisany w formacie Markdown

Step 7- Zamień kod rzutki w pliku lib / main.dart na poniższy kod -

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application',
         theme: ThemeData(
            primarySwatch: Colors.blue,
         ),
         home: MyHomePage(title: 'Home page'),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;

   @override
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title),
         ),
         body: Center(
            child:
            Text(
               'Hello World',
            )
         ),
      );
   }
}

Pozwól nam zrozumieć wiersz kodu strzałki po linii.

  • Line 1- importuje opakowanie flutter, materiał . Materiał jest pakietem flutter do tworzenia interfejsu użytkownika zgodnie z wytycznymi Material design określonymi przez Androida.

  • Line 3- To jest punkt wejścia do aplikacji Flutter. Wzywa runApp funkcji i przekazać przedmiot MojaApl klasie. Celem funkcji runApp jest dołączenie danego widżetu do ekranu.

  • Line 5-17- Widget służy do tworzenia interfejsu użytkownika w frameworku flutter. StatelessWidget to widget, który nie utrzymuje żadnego stanu widgetu. MyApp rozszerza StatelessWidget i zastępuje jego metodę kompilacji . Celem metody kompilacji jest utworzenie części interfejsu użytkownika aplikacji. Tutaj metoda kompilacji używa MaterialApp , widżetu do tworzenia interfejsu użytkownika poziomu głównego aplikacji. Ma trzy właściwości - tytuł, temat i dom .

    • title to tytuł aplikacji

    • motyw jest tematem widżetu. Tutaj ustawiamy niebieski jako ogólny kolor aplikacji za pomocą klasy ThemeData i jej właściwości primarySwatch .

    • home to wewnętrzny interfejs użytkownika aplikacji, dla którego ustawiliśmy kolejny widget, MyHomePage

  • Line 19 - 38- MyHomePage jest taka sama jak MojaApl wyjątkiem zwraca Scaffold widget. Scaffold to widget najwyższego poziomu, obok widgetu MaterialApp, służący do tworzenia materiałów projektowych zgodnych z interfejsem użytkownika. Ma dwie ważne właściwości, appBar, aby pokazać nagłówek aplikacji i treść, aby pokazać rzeczywistą zawartość aplikacji. AppBar to kolejny widget do renderowania nagłówka aplikacji i użyliśmy go we właściwości appBar . We właściwości body użyliśmy widżetu Center , który wyśrodkowuje widżet podrzędny. Tekst jest ostatnim i najbardziej wewnętrznym widżetem wyświetlającym tekst i jest wyświetlany na środku ekranu.

Step 8 - Teraz uruchom aplikację za pomocą, Run → Run main.dart

Step 9 - Wreszcie dane wyjściowe aplikacji są następujące -

W tym rozdziale omówimy architekturę frameworka Flutter.

Widgety

Podstawową koncepcją frameworka Flutter jest In Flutter, Everything is a widget. Widżety to w zasadzie komponenty interfejsu użytkownika używane do tworzenia interfejsu użytkownika aplikacji.

We Flutterze sama aplikacja jest widżetem. Aplikacja jest widżetem najwyższego poziomu, a jej interfejs użytkownika jest tworzony przy użyciu jednego lub więcej elementów podrzędnych (widżetów), które ponownie są budowane przy użyciu widgetów podrzędnych. Tocomposability Funkcja pomaga nam stworzyć interfejs użytkownika o dowolnej złożoności.

Na przykład hierarchia widżetów aplikacji hello world (utworzonej w poprzednim rozdziale) jest taka, jak określono na poniższym diagramie -

Tutaj warte uwagi są następujące punkty -

  • MyApp to widget utworzony przez użytkownika, który jest tworzony przy użyciu natywnego widgetu Flutter, MaterialApp .

  • MaterialApp ma właściwość home do określenia interfejsu użytkownika strony głównej, która jest ponownie utworzonym przez użytkownika widżetem MyHomePage .

  • MyHomePage jest budowany przy użyciu innego natywnego widżetu Flutter , Scaffold

  • Rusztowanie ma dwie właściwości - body i appBar

  • body służy do określenia głównego interfejsu użytkownika, a appBar służy do określenia interfejsu użytkownika w nagłówku

  • Header UI jest budowany przy użyciu natywnego widżetu Flutter , AppBar i Body UI jest budowany przy użyciu widżetu Center .

  • Centrum widget ma właściwość, Dziecko , które odnosi się do rzeczywistej zawartości i jest to build przy użyciu tekstu widget

Gesty

Widżety Flutter obsługują interakcję za pośrednictwem specjalnego widżetu GestureDetector . GestureDetector to niewidoczny widget mający możliwość przechwytywania interakcji użytkownika, takich jak stukanie, przeciąganie itp. Widgetu podrzędnego. Wiele natywnych widżetów Fluttera obsługuje interakcję poprzez użycie GestureDetector . Możemy również włączyć funkcję interaktywną do istniejącego widżetu, komponując go za pomocą widżetu GestureDetector . Osobno nauczymy się gestów w kolejnych rozdziałach.

Pojęcie państwa

Widżety Flutter wspierają utrzymanie stanu poprzez dostarczanie specjalnego widżetu StatefulWidget . Widget musi pochodzić z widżetu StatefulWidget, aby obsługiwać obsługę stanu, a wszystkie inne widżety powinny pochodzić z StatefulWidget . Widżety Flutter toreactivew języku ojczystym. Jest to podobne do reagowania, a StatefulWidget będzie automatycznie renderowany ponownie za każdym razem, gdy zmieni się jego stan wewnętrzny. Ponowne renderowanie jest optymalizowane poprzez znalezienie różnicy między starym i nowym interfejsem widgetu i renderowanie tylko niezbędnych zmian

Warstwy

Najważniejszą koncepcją frameworka Flutter jest to, że framework jest zgrupowany w wielu kategoriach pod względem złożoności i wyraźnie ułożony w warstwy o malejącej złożoności. Warstwa jest budowana przy użyciu jej bezpośredniej warstwy następnego poziomu. Najwyższą warstwą jest widżet specyficzny dla Androida i iOS . Następna warstwa zawiera wszystkie trzepoczące natywne widżety. Następną warstwą jest warstwa renderowania , która jest komponentem renderującym niskiego poziomu i renderuje wszystko w aplikacji flutter. Warstwy sprowadzają się do podstawowego kodu platformy

Ogólny przegląd warstwy we Flutterze przedstawiono na poniższym diagramie -

Poniższe punkty podsumowują architekturę Flutter -

  • We Flutterze wszystko jest widżetem, a złożony widżet składa się z już istniejących widżetów.

  • Funkcje interaktywne można włączyć w razie potrzeby za pomocą widżetu GestureDetector .

  • Stan widgetu można w razie potrzeby utrzymywać za pomocą widgetu StatefulWidget .

  • Flutter oferuje projektowanie warstwowe, dzięki czemu dowolną warstwę można zaprogramować w zależności od złożoności zadania.

Szczegółowo omówimy wszystkie te koncepcje w kolejnych rozdziałach.

Dart to język programowania ogólnego przeznaczenia typu open source. Jest pierwotnie opracowany przez Google. Dart to język obiektowy ze składnią w stylu C. Obsługuje koncepcje programowania, takie jak interfejsy, klasy, w przeciwieństwie do innych języków programowania Dart nie obsługuje tablic. Kolekcje Dart mogą służyć do replikowania struktur danych, takich jak tablice, typy ogólne i opcjonalne wpisywanie.

Poniższy kod przedstawia prosty program Dart -

void main() {
   print("Dart language is easy to learn");
}

Zmienne i typy danych

Zmienna nosi nazwę lokalizacji przechowywania, a typy danych po prostu odnoszą się do typu i rozmiaru danych powiązanych ze zmiennymi i funkcjami.

Dart używa słowa kluczowego var do zadeklarowania zmiennej. Składnię var zdefiniowano poniżej,

var name = 'Dart';

Ostateczna i const kluczowe są używane do stałych deklaracji. Są zdefiniowane jak poniżej -

void main() {
   final a = 12;
   const pi = 3.14;
   print(a);
   print(pi);
}

Język Dart obsługuje następujące typy danych -

  • Numbers - Służy do reprezentowania literałów numerycznych - Integer i Double.

  • Strings- Reprezentuje ciąg znaków. Wartości ciągów są podawane w pojedynczych lub podwójnych cudzysłowach.

  • Booleans- Dart używa słowa kluczowego bool do reprezentowania wartości boolowskich - prawda i fałsz.

  • Lists and Maps- Służy do reprezentowania zbioru obiektów. Prostą listę można zdefiniować, jak poniżej -.

void main() {
   var list = [1,2,3,4,5];
   print(list);
}

Lista pokazana powyżej tworzy listę [1, 2, 3, 4, 5].

Mapę można zdefiniować, jak pokazano tutaj -

void main() {
   var mapping = {'id': 1,'name':'Dart'};
   print(mapping);
}
  • Dynamic- Jeśli typ zmiennej nie jest zdefiniowany, to jej domyślny typ jest dynamiczny. Poniższy przykład ilustruje zmienną typu dynamicznego -

void main() {
   dynamic name = "Dart";
   print(name);
}

Podejmowanie decyzji i pętle

Blok decyzyjny ocenia warunek przed wykonaniem instrukcji. Dart obsługuje instrukcje If, ​​If..else i switch.

Pętle służą do powtarzania bloku kodu, dopóki nie zostanie spełniony określony warunek. Dart obsługuje pętle for, for..in, while i do..while.

Zrozummy prosty przykład dotyczący użycia instrukcji sterujących i pętli -

void main() {
   for( var i = 1 ; i <= 10; i++ ) {
      if(i%2==0) {
         print(i);
      }
   }
}

Powyższy kod wypisuje parzyste liczby od 1 do 10.

Funkcje

Funkcja to grupa instrukcji, które razem wykonują określone zadanie. Przyjrzyjmy się prostej funkcji w Dart, jak pokazano tutaj -

void main() {
   add(3,4);
}
void add(int a,int b) {
   int c;
   c = a+b;
   print(c);
}

Powyższa funkcja dodaje dwie wartości i generuje 7 jako wynik.

Programowanie obiektowe

Dart to język zorientowany obiektowo. Obsługuje funkcje programowania obiektowego, takie jak klasy, interfejsy itp.

Klasa to plan tworzenia obiektów. Definicja klasy obejmuje:

  • Fields
  • Getters i setters
  • Constructors
  • Functions

Teraz stwórzmy prostą klasę, używając powyższych definicji -

class Employee {
   String name;
   
   //getter method
   String get emp_name {
      return name;
   }
   //setter method
   void set emp_name(String name) {
      this.name = name;
   }
   //function definition
   void result() {
      print(name);
   }
}
void main() {
   //object creation
   Employee emp = new Employee();
   emp.name = "employee1";
   emp.result(); //function call
}

Jak dowiedzieliśmy się z poprzedniego rozdziału, widżety są wszystkim we frameworku Flutter. Dowiedzieliśmy się już, jak tworzyć nowe widżety w poprzednich rozdziałach.

W tym rozdziale zrozumiemy rzeczywistą koncepcję tworzenia widżetów i różnych typów widżetów dostępnych we frameworku Flutter .

Sprawdźmy widżet MyHomePage aplikacji Hello World . Kod do tego celu jest podany poniżej -

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar(title: Text(this.title), ), 
         body: Center(child: Text( 'Hello World',)),
      );
   }
}

Tutaj stworzyliśmy nowy widżet, rozszerzając StatelessWidget .

Należy zauważyć, że StatelessWidget wymaga tylko jednej kompilacji metody do zaimplementowania w swojej klasie pochodnej. Metoda kompilacji pobiera środowisko kontekstowe niezbędne do tworzenia widgetów za pomocą parametru BuildContext i zwraca widget, który tworzy.

W kodzie użyliśmy title jako jednego z argumentów konstruktora, a także użyliśmy klucza jako innego argumentu. Tytuł jest używany do wyświetlania tytułu i Klucz służy do identyfikacji widżet w środowisku kompilacji.

Tutaj build metoda nazywa gromadzeniu metodę rusztowań , co z kolei wywołuje gromadzenie metodę AppBar i Centrum do budowania jego interfejs użytkownika.

Na koniec metoda kompilacji Center wywołuje metodę budowania tekstu .

Aby lepiej zrozumieć, wizualną reprezentację tego samego podano poniżej -

Wizualizacja tworzenia widżetów

We Flutterze widżety można pogrupować w wiele kategorii na podstawie ich funkcji, jak podano poniżej -

  • Widżety specyficzne dla platformy
  • Układ widżetów
  • Widżety konserwacji stanu
  • Niezależne od platformy / podstawowe widżety

Omówmy teraz szczegółowo każdy z nich.

Widżety specyficzne dla platformy

Flutter ma widżety specyficzne dla konkretnej platformy - Android lub iOS.

Widżety dla systemu Android są projektowane zgodnie z wytycznymi dotyczącymi projektowania materiałów opracowanymi przez system operacyjny Android. Widżety dla systemu Android są nazywane widżetami Material .

Specyficzne widżety iOS zostały zaprojektowane zgodnie z wytycznymi dotyczącymi interfejsu użytkownika przez Apple i nazywane są widżetami Cupertino .

Oto niektóre z najczęściej używanych widżetów materiałów -

  • Scaffold
  • AppBar
  • BottomNavigationBar
  • TabBar
  • TabBarView
  • ListTile
  • RaisedButton
  • FloatingActionButton
  • FlatButton
  • IconButton
  • DropdownButton
  • PopupMenuButton
  • ButtonBar
  • TextField
  • Checkbox
  • Radio
  • Switch
  • Slider
  • Selektory daty i godziny
  • SimpleDialog
  • AlertDialog

Oto niektóre z najczęściej używanych widżetów Cupertino -

  • CupertinoButton
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoTimerPicker
  • CupertinoNavigationBar
  • CupertinoTabBar
  • CupertinoTabScaffold
  • CupertinoTabView
  • CupertinoTextField
  • CupertinoDialog
  • CupertinoDialogAction
  • CupertinoFullscreenDialogTransition
  • CupertinoPageScaffold
  • CupertinoPageTransition
  • CupertinoActionSheet
  • CupertinoActivityIndicator
  • CupertinoAlertDialog
  • CupertinoPopupSurface
  • CupertinoSlider

Układ widżetów

We Flutterze widżet można utworzyć, komponując jeden lub więcej widgetów. Aby połączyć wiele widżetów w jeden widżet, Flutter zapewnia dużą liczbę widżetów z funkcją układu. Na przykład widget podrzędny można wyśrodkować za pomocą widgetu Centrum .

Oto niektóre z popularnych widżetów układu -

  • Container- Prostokątne pudełko ozdobione widżetami BoxDecoration z tłem, obramowaniem i cieniem.

  • Center - Wyśrodkuj widżet podrzędny.

  • Row - Ułóż swoje dzieci w kierunku poziomym.

  • Column - Ułóż swoje dzieci w kierunku pionowym.

  • Stack - Ułóż jeden nad drugim.

Szczegółowo sprawdzimy widżety układu w nadchodzącym rozdziale Wprowadzenie do widgetów układu .

Widżety konserwacji stanu

We Flutterze wszystkie widżety są pochodnymi StatelessWidget lub StatefulWidget .

Widget pochodzący z StatelessWidget nie ma żadnych informacji o stanie, ale może zawierać widget pochodzący z StatefulWidget . Dynamiczna natura aplikacji polega na interaktywnym zachowaniu widżetów i zmianach stanu podczas interakcji. Na przykład dotknięcie przycisku licznika zwiększy / zmniejszy stan wewnętrzny licznika o jeden, a reaktywny charakter widżetu Flutter spowoduje automatyczne ponowne renderowanie widżetu przy użyciu nowych informacji o stanie.

We will learn the concept of StatefulWidget widgets in detail in the upcoming State management chapter.

Platform independent / basic widgets

Flutter provides large number of basic widgets to create simple as well as complex user interface in a platform independent manner. Let us see some of the basic widgets in this chapter.

Text

Text widget is used to display a piece of string. The style of the string can be set by using style property and TextStyle class. The sample code for this purpose is as follows −

Text('Hello World!', style: TextStyle(fontWeight: FontWeight.bold))

Text widget has a special constructor, Text.rich, which accepts the child of type TextSpan to specify the string with different style. TextSpan widget is recursive in nature and it accepts TextSpan as its children. The sample code for this purpose is as follows −

Text.rich( 
   TextSpan( 
      children: <TextSpan>[ 
         TextSpan(text: "Hello ", style:  
         TextStyle(fontStyle: FontStyle.italic)),  
         TextSpan(text: "World", style: 
         TextStyle(fontWeight: FontWeight.bold)),  
      ], 
   ), 
)

The most important properties of the Text widget are as follows −

  • maxLines, int − Maximum number of lines to show

  • overflow, TextOverFlow − Specify how visual overflow is handled using TextOverFlow class

  • style, TextStyle − Specify the style of the string using TextStyle class

  • textAlign, TextAlign − Alignment of the text like right, left, justify, etc., using TextAlign class

  • textDirection, TextDirection − Direction of text to flow, either left-to-right or right-to-left

Image

Image widget is used to display an image in the application. Image widget provides different constructors to load images from multiple sources and they are as follows −

  • Image − Generic image loader using ImageProvider

  • Image.asset − Load image from flutter project’s assets

  • Image.file − Load image from system folder

  • Image.memory − Load image from memory

  • Image.Network − Load image from network

The easiest option to load and display an image in Flutter is by including the image as assets of the application and load it into the widget on demand.

  • Create a folder, assets in the project folder and place the necessary images.

  • Specify the assets in the pubspec.yaml as shown below −

flutter: 
   assets: 
      - assets/smiley.png
  • Now, load and display the image in the application.

Image.asset('assets/smiley.png')
  • The complete source code of MyHomePage widget of the hello world application and the result is as shown below −.

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( title: Text(this.title), ), 
         body: Center( child: Image.asset("assets/smiley.png")),
      ); 
   }
}

The loaded image is as shown below −

The most important properties of the Image widget are as follows −

  • image, ImageProvider − Actual image to load

  • width, double − Width of the image

  • height, double − Height of the image

  • alignment, AlignmentGeometry − How to align the image within its bounds

Icon

Icon widget is used to display a glyph from a font described in IconData class. The code to load a simple email icon is as follows −

Icon(Icons.email)

The complete source code to apply it in hello world application is as follows −

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center( child: Icon(Icons.email)),
      );
   }
}

The loaded icon is as shown below −

Since the core concept of Flutter is Everything is widget, Flutter incorporates a user interface layout functionality into the widgets itself. Flutter provides quite a lot of specially designed widgets like Container, Center, Align, etc., only for the purpose of laying out the user interface. Widgets build by composing other widgets normally use layout widgets. Let use learn the Flutter layout concept in this chapter.

Type of Layout Widgets

Layout widgets can be grouped into two distinct category based on its child −

  • Widget supporting a single child
  • Widget supporting multiple child

Let us learn both type of widgets and its functionality in the upcoming sections.

Single Child Widgets

In this category, widgets will have only one widget as its child and every widget will have a special layout functionality.

For example, Center widget just centers it child widget with respect to its parent widget and Container widget provides complete flexibility to place it child at any given place inside it using different option like padding, decoration, etc.,

Single child widgets are great options to create high quality widget having single functionality such as button, label, etc.,

The code to create a simple button using Container widget is as follows −

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

Here, we have used two widgets – a Container widget and a Text widget. The result of the widget is as a custom button as shown below −

Let us check some of the most important single child layout widgets provided by Flutter

  • Padding − Used to arrange its child widget by the given padding. Here, padding can be provided by EdgeInsets class.

  • Align − Align its child widget within itself using the value of alignment property. The value for alignment property can be provided by FractionalOffset class. The FractionalOffset class specifies the offsets in terms of a distance from the top left.

Some of the possible values of offsets are as follows −

  • FractionalOffset(1.0, 0.0) represents the top right.

  • FractionalOffset(0.0, 1.0) represents the bottom left.

A sample code about offsets is shown below −

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox − It scales the child widget and then positions it according to the specified fit.

  • AspectRatio − It attempts to size the child widget to the specified aspect ratio

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

Our hello world application is using material based layout widgets to design the home page. Let us modify our hello world application to build the home page using basic layout widgets as specified below −

  • Container − Generic, single child, box based container widget with alignment, padding, border and margin along with rich styling features.

  • Center − Simple, Single child container widget, which centers its child widget.

The modified code of the MyHomePage and MyApp widget is as below −

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

Here,

  • Container widget is the top level or root widget. Container is configured using decoration and padding property to layout its content.

  • BoxDecoration has many properties like color, border, etc., to decorate the Container widget and here, color is used to set the color of the container.

  • padding of the Container widget is set by using dgeInsets class, which provides the option to specify the padding value.

  • Center is the child widget of the Container widget. Again, Text is the child of the Center widget. Text is used to show message and Center is used to center the text message with respect to the parent widget, Container.

The final result of the code given above is a layout sample as shown below −

Multiple Child Widgets

In this category, a given widget will have more than one child widgets and the layout of each widget is unique.

For example, Row widget allows the laying out of its children in horizontal direction, whereas Column widget allows laying out of its children in vertical direction. By composing Row and Column, widget with any level of complexity can be built.

Let us learn some of the frequently used widgets in this section.

  • Row − Allows to arrange its children in a horizontal manner.

  • Column − Allows to arrange its children in a vertical manner.

  • ListView − Allows to arrange its children as list.

  • GridView − Allows to arrange its children as gallery.

  • Expanded − Used to make the children of Row and Column widget to occupy the maximum possible area.

  • Table − Table based widget.

  • Flow − Flow based widget.

  • Stack − Stack based widget.

Advanced Layout Application

In this section, let us learn how to create a complex user interface of product listing with custom design using both single and multiple child layout widgets.

For this purpose, follow the sequence given below −

  • Create a new Flutter application in Android studio, product_layout_app.

  • Replace the main.dart code with folowing code −

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • We have created MyHomePage widget by extending StatelessWidget instead of default StatefulWidget and then removed the relevant code.

  • Now, create a new widget, ProductBox according to the specified design as shown below −

  • The code for the ProductBox is as follows.

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • Please observe the following in the code −

  • ProductBox has used four arguments as specified below −

    • name - Product name

    • description - Product description

    • price - Price of the product

    • image - Image of the product

  • ProductBox uses seven build-in widgets as specified below −

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBox is designed using the above mentioned widget. The arrangement or hierarchy of the widget is specified in the diagram shown below −

  • Now, place some dummy image (see below) for product information in the assets folder of the application and configure the assets folder in the pubspec.yaml file as shown below −

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

Finally, Use the ProductBox widget in the MyHomePage widget as specified below −

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • Tutaj użyliśmy ProductBox jako elementów podrzędnych widżetu ListView .

  • Pełny kod (main.dart) aplikacji układu produktu (product_layout_app) jest następujący -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

Końcowy wynik aplikacji jest następujący -

Gesty są przede wszystkim sposobem interakcji użytkownika z aplikacją mobilną (lub dowolnym urządzeniem dotykowym). Gesty są ogólnie definiowane jako wszelkie fizyczne działania / ruchy użytkownika mające na celu aktywację określonego sterowania urządzeniem mobilnym. Gesty są tak proste, jak dotknięcie ekranu urządzenia mobilnego, aby wykonać bardziej złożone czynności używane w aplikacjach do gier.

W tym miejscu wymieniono niektóre z powszechnie używanych gestów -

  • Tap - Krótkie dotknięcie powierzchni urządzenia opuszkiem palca, a następnie puszczenie opuszki.

  • Double Tap - Dwukrotne stukanie w krótkim czasie.

  • Drag - Dotknięcie powierzchni urządzenia opuszkiem palca, a następnie równomierne przesuwanie opuszkiem, a na końcu puszczenie opuszki.

  • Flick - Podobny do przeciągania, ale robiąc to w szybszy sposób.

  • Pinch - Ściskanie powierzchni urządzenia dwoma palcami.

  • Spread/Zoom - Przeciwieństwo szczypania.

  • Panning - Dotykanie powierzchni urządzenia opuszkiem palca i przesuwanie go w dowolnym kierunku bez puszczania opuszki.

Flutter zapewnia doskonałe wsparcie dla wszystkich rodzajów gestów dzięki ekskluzywnemu widżetowi, GestureDetector. GestureDetector to niewizualny widżet używany głównie do wykrywania gestów użytkownika. Aby zidentyfikować gest skierowany na widget, widget można umieścić wewnątrz widgetu GestureDetector. GestureDetector przechwyci gest i wywoła wiele zdarzeń na podstawie gestu.

Niektóre gesty i odpowiadające im zdarzenia podano poniżej -

  • Tap
    • onTapDown
    • onTapUp
    • onTap
    • onTapCancel
  • Podwójne wciśnięcie
    • onDoubleTap
  • Długie naciśnięcie
    • onLongPress
  • Przeciągnij w pionie
    • onVerticalDragStart
    • onVerticalDragUpdate
    • onVerticalDragEnd
  • Przeciąganie w poziomie
    • onHorizontalDragStart
    • onHorizontalDragUpdate
    • onHorizontalDragEnd
  • Pan
    • onPanStart
    • onPanUpdate
    • onPanEnd

Teraz zmodyfikujmy aplikację Hello world, aby zawierała funkcję wykrywania gestów i spróbujmy zrozumieć koncepcję.

  • Zmień treść widżetu MyHomePage, jak pokazano poniżej -

body: Center( 
   child: GestureDetector( 
      onTap: () { 
         _showDialog(context); 
      }, 
      child: Text( 'Hello World', ) 
   ) 
),
  • Zwróć uwagę, że tutaj umieściliśmy widget GestureDetector powyżej widgetu Tekst w hierarchii widgetów, przechwyciliśmy zdarzenie onTap, a na koniec pokazaliśmy okno dialogowe.

  • Zaimplementuj funkcję * _showDialog *, aby wyświetlić okno dialogowe, gdy użytkownik przejdzie do wiadomości hello world . Używa ogólnego widżetu showDialog i AlertDialog do tworzenia nowego widżetu okna dialogowego. Kod pokazano poniżej -

// user defined function void _showDialog(BuildContext context) { 
   // flutter defined function 
   showDialog( 
      context: context, builder: (BuildContext context) { 
         // return object of type Dialog
         return AlertDialog( 
            title: new Text("Message"), 
            content: new Text("Hello World"),   
            actions: <Widget>[ 
               new FlatButton( 
                  child: new Text("Close"),  
                  onPressed: () {   
                     Navigator.of(context).pop();  
                  }, 
               ), 
            ], 
         ); 
      }, 
   ); 
}
  • Aplikacja załaduje się ponownie w urządzeniu za pomocą funkcji Hot Reload. Teraz wystarczy kliknąć wiadomość Hello World, a pojawi się poniższe okno dialogowe -

  • Teraz zamknij okno dialogowe, klikając opcję zamykania w oknie dialogowym.

  • Kompletny kod (main.dart) wygląda następująco -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application.    
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application', 
         theme: ThemeData( primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   // user defined function 
   void _showDialog(BuildContext context) { 
      // flutter defined function showDialog( 
         context: context, builder: (BuildContext context) { 
            // return object of type Dialog return AlertDialog(
               title: new Text("Message"), 
               content: new Text("Hello World"),   
               actions: <Widget>[
                  new FlatButton(
                     child: new Text("Close"), 
                     onPressed: () {   
                        Navigator.of(context).pop();  
                     }, 
                  ), 
               ],
            );
         },
      );
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center(
            child: GestureDetector( 
               onTap: () {
                  _showDialog(context);
               },
            child: Text( 'Hello World', )
            )
         ),
      );
   }
}

Wreszcie Flutter zapewnia również mechanizm wykrywania gestów niskiego poziomu za pośrednictwem widżetu Listener . Wykryje wszystkie interakcje użytkownika, a następnie wysyła następujące zdarzenia -

  • PointerDownEvent
  • PointerMoveEvent
  • PointerUpEvent
  • PointerCancelEvent

Flutter zapewnia również niewielki zestaw widżetów do wykonywania określonych i zaawansowanych gestów. Widżety są wymienione poniżej -

  • Dismissible - Obsługuje gest szybkiego ruchu, aby odrzucić widżet.

  • Draggable - Obsługuje gest przeciągania, aby przenieść widżet.

  • LongPressDraggable - Obsługuje gest przeciągania, aby przenieść widżet, gdy jego widżet nadrzędny również można przeciągać.

  • DragTarget- Akceptuje dowolny widget Draggable

  • IgnorePointer - Ukrywa widżet i jego elementy podrzędne przed procesem wykrywania gestów.

  • AbsorbPointer - Zatrzymuje sam proces wykrywania gestów, a zatem każdy nakładający się widżet również nie może uczestniczyć w procesie wykrywania gestów, a zatem żadne zdarzenie nie jest zgłaszane.

  • Scrollable - Obsługa przewijania treści dostępnych wewnątrz widżetu.

Zarządzanie stanem w aplikacji jest jednym z najważniejszych i niezbędnych procesów w cyklu życia aplikacji.

Rozważmy prostą aplikację do koszyka.

  • Użytkownik będzie logował się przy użyciu swoich poświadczeń do aplikacji.

  • Gdy użytkownik jest zalogowany, aplikacja powinna zachować szczegóły zalogowanego użytkownika na całym ekranie.

  • Ponownie, gdy użytkownik wybierze produkt i zapisze go w koszyku, informacje o koszyku powinny pozostać między stronami do momentu, gdy użytkownik wyewidencjonuje koszyk.

  • Informacje o użytkowniku i jego koszyku w każdym przypadku nazywane są stanem aplikacji w tym przypadku.

Zarządzanie stanem można podzielić na dwie kategorie w zależności od czasu trwania określonego stanu w aplikacji.

  • Ephemeral- Trwać przez kilka sekund, jak aktualny stan animacji lub pojedyncza strona, taka jak aktualna ocena produktu. Flutter obsługuje go poprzez StatefulWidget.

  • app state- Ostatnia dla całej aplikacji, takiej jak dane zalogowanego użytkownika, informacje o koszyku itp., Flutter obsługuje jej poprzez scoped_model.

Nawigacja i wyznaczanie tras

W każdej aplikacji przechodzenie z jednej strony / ekranu na drugą definiuje przepływ pracy aplikacji. Sposób, w jaki obsługiwana jest nawigacja w aplikacji, nazywa się routingiem. Flutter zapewnia podstawową klasę routingu - MaterialPageRoute oraz dwie metody - Navigator.push i Navigator.pop, do definiowania przepływu pracy aplikacji.

MaterialPageRoute

MaterialPageRoute to widżet używany do renderowania interfejsu użytkownika poprzez zastąpienie całego ekranu animacją specyficzną dla platformy.

MaterialPageRoute(builder: (context) => Widget())

W tym przypadku program budujący zaakceptuje funkcję do zbudowania swojej zawartości, dostarczając bieżący kontekst aplikacji.

Navigation.push

Navigation.push służy do nawigacji do nowego ekranu za pomocą widżetu MaterialPageRoute.

Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );

Navigation.pop

Navigation.pop służy do przechodzenia do poprzedniego ekranu.

Navigator.pop(context);

Stwórzmy nową aplikację, aby lepiej zrozumieć koncepcję nawigacji.

Utwórz nową aplikację Flutter w Android Studio, product_nav_app

  • Skopiuj folder asset z product_nav_app do product_state_app i dodaj zasoby w pliku pubspec.yaml.

flutter:
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Zastąp domyślny kod startowy (main.dart) naszym kodem startowym.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) { 
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Product state demo home page'
         ),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: Text('Hello World',)
         ), 
      ); 
   } 
}
  • Utwórzmy klasę produktu, aby uporządkować informacje o produkcie.

class Product { 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
}
  • Napiszmy metodę getProducts w klasie Product, aby wygenerować nasze fikcyjne rekordy produktów.

static List<Product> getProducts() {
   List<Product> items = <Product>[]; 
   
   items.add(
      Product( 
         "Pixel", 
         "Pixel is the most feature-full phone ever", 800, 
         "pixel.png"
      )
   ); 
   items.add(
      Product(
         "Laptop", 
         "Laptop is most productive development tool", 
         2000, "
         laptop.png"
      )
   ); 
   items.add(
      Product( 
         "Tablet", 
         "Tablet is the most useful device ever for meeting", 
         1500, 
         "tablet.png"
      )
   ); 
   items.add(
      Product( 
         "Pendrive", 
         "Pendrive is useful storage medium",
         100, 
         "pendrive.png"
      )
   ); 
   items.add(
      Product( 
         "Floppy Drive", 
         "Floppy drive is useful rescue storage medium", 
         20, 
         "floppy.png"
      )
   ); 
   return items; 
}
import product.dart in main.dart
import 'Product.dart';
  • Dołączmy nasz nowy widżet RatingBox.

class RatingBox extends StatefulWidget {
   @override 
   _RatingBoxState createState() =>_RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> {
   int _rating = 0; 
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   } 
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   }
   void _setRatingAsThree() {
      setState(() {
         _rating = 3;
      });
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 2? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   }
}
  • Zmodyfikujmy nasz widżet ProductBox, aby działał z naszą nową klasą Product.

class ProductBox extends StatelessWidget {    
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), 
                        child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[
                              Text(this.item.name, 
                              style: TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   }
}

Przepiszmy nasz widget MyHomePage, aby działał z modelem Product i wyświetlał wszystkie produkty za pomocą ListView.

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( appBar: AppBar(title: Text("Product Navigation")), 
      body: ListView.builder( 
         itemCount: items.length, 
         itemBuilder: (context, index) {
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push( 
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      )); 
   } 
}

Tutaj skorzystaliśmy z MaterialPageRoute, aby przejść do strony szczegółów produktu.

  • Teraz dodajmy ProductPage, aby wyświetlić szczegóły produktu.

class ProductPage extends StatelessWidget { 
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container(
               padding: EdgeInsets.all(0), 
               child: Column(
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded(
                        child: Container(
                           padding: EdgeInsets.all(5), 
                           child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[
                                 Text(
                                    this.item.name, style: TextStyle(
                                       fontWeight: FontWeight.bold
                                    )
                                 ), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(),
                              ], 
                           )
                        )
                     )
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}

Pełny kod aplikacji wygląda następująco -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class Product {
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
   
   static List<Product> getProducts() {
      List<Product> items = <Product>[]; 
      items.add(
         Product(
            "Pixel", 
            "Pixel is the most featureful phone ever", 
            800, 
            "pixel.png"
         )
      );
      items.add(
         Product(
            "Laptop", 
            "Laptop is most productive development tool", 
            2000, 
            "laptop.png"
         )
      ); 
      items.add(
         Product(
            "Tablet", 
            "Tablet is the most useful device ever for meeting", 
            1500, 
            "tablet.png"
         )
      ); 
      items.add(
         Product( 
            "Pendrive", 
            "iPhone is the stylist phone ever", 
            100, 
            "pendrive.png"
         )
      ); 
      items.add(
         Product(
            "Floppy Drive", 
            "iPhone is the stylist phone ever", 
            20, 
            "floppy.png"
         )
      ); 
      items.add(
         Product(
            "iPhone", 
            "iPhone is the stylist phone ever", 
            1000, 
            "iphone.png"
         )
      ); 
      return items; 
   }
}
class MyApp extends StatelessWidget {
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Product Navigation demo home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: ListView.builder( 
            itemCount: items.length, 
            itemBuilder: (context, index) { 
               return GestureDetector( 
                  child: ProductBox(item: items[index]), 
                  onTap: () { 
                     Navigator.push( 
                        context, 
                        MaterialPageRoute( 
                           builder: (context) => ProductPage(item: items[index]), 
                        ), 
                     ); 
                  }, 
               ); 
            }, 
         )
      ); 
   }
} 
class ProductPage extends StatelessWidget {
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container( 
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[ 
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() => _RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0;
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   } 
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1 ? Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 2 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     )
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
} 
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  ) 
               ]
            ), 
         )
      ); 
   } 
}

Uruchom aplikację i kliknij dowolną pozycję produktu. Wyświetli odpowiednią stronę szczegółów. Na stronę główną możemy przejść klikając przycisk Wstecz. Strona listy produktów i strona szczegółów produktu w aplikacji są wyświetlane w następujący sposób -

Animacja to złożona procedura w dowolnej aplikacji mobilnej. Pomimo swojej złożoności, Animation podnosi komfort użytkowania na nowy poziom i zapewnia bogatą interakcję z użytkownikiem. Animacja ze względu na swoje bogactwo staje się integralną częścią nowoczesnej aplikacji mobilnej. Platforma Flutter uznaje znaczenie animacji i zapewnia prostą i intuicyjną strukturę do tworzenia wszystkich typów animacji.

Wprowadzenie

Animacja to proces pokazania serii obrazów / obrazów w określonej kolejności w określonym czasie, aby stworzyć iluzję ruchu. Najważniejsze aspekty animacji są następujące -

  • Animacja ma dwie różne wartości: wartość początkową i wartość końcową. Animacja zaczyna się od wartości początkowej i przechodzi przez szereg wartości pośrednich, a na końcu kończy się na wartościach końcowych. Na przykład, aby animować znikanie widżetu, wartością początkową będzie pełne krycie, a wartością końcową będzie zerowe krycie.

  • Wartości pośrednie mogą mieć charakter liniowy lub nieliniowy (krzywa) i można je konfigurować. Zrozum, że animacja działa zgodnie z konfiguracją. Każda konfiguracja zapewnia inny wygląd animacji. Na przykład zanikanie widżetu będzie miało charakter liniowy, podczas gdy odbijanie piłki będzie miało charakter nieliniowy.

  • Czas trwania procesu animacji wpływa na szybkość (powolność lub szybkość) animacji.

  • Możliwość sterowania procesem animacji, jak uruchamianie animacji, zatrzymywanie animacji, powtarzanie animacji do określonej liczby razy, cofanie procesu animacji itp.,

  • We Flutterze system animacji nie wykonuje żadnej prawdziwej animacji. Zamiast tego zapewnia tylko wartości wymagane w każdej klatce do renderowania obrazów.

Klasy oparte na animacji

System animacji Flutter oparty jest na obiektach Animation. Podstawowe klasy animacji i ich użycie są następujące:

Animacja

Generuje interpolowane wartości między dwiema liczbami w określonym czasie. Najpopularniejsze klasy animacji to -

  • Animation<double> - interpoluje wartości między dwoma liczbami dziesiętnymi

  • Animation<Color> - interpoluj kolory między dwoma kolorami

  • Animation<Size> - interpoluj rozmiary między dwoma rozmiarami

  • AnimationController- Specjalny obiekt animacji do sterowania samą animacją. Generuje nowe wartości, gdy aplikacja jest gotowa na nową ramkę. Obsługuje animację liniową, a wartość zaczyna się od 0,0 do 1,0

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);

Tutaj kontroler kontroluje animację, a opcja czasu trwania kontroluje czas trwania procesu animacji. vsync to specjalna opcja używana do optymalizacji zasobów używanych w animacji.

CurvedAnimation

Podobny do AnimationController, ale obsługuje animację nieliniową. CurvedAnimation może być używany razem z obiektem Animation, jak poniżej -

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)

Tween <T>

Pochodzi z Animatable <T> i służy do generowania liczb między dowolnymi dwiema liczbami innymi niż 0 i 1. Może być używany razem z obiektem Animation przy użyciu metody animate i przekazywania rzeczywistego obiektu Animation.

AnimationController controller = AnimationController( 
   duration: const Duration(milliseconds: 1000), 
vsync: this); Animation<int> customTween = IntTween(
   begin: 0, end: 255).animate(controller);
  • Tween może być również używany wraz z CurvedAnimation, jak poniżej -

AnimationController controller = AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this); 
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); 
Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve);

Tutaj kontroler jest rzeczywistym kontrolerem animacji. krzywa zapewnia typ nieliniowości, a customTween zapewnia niestandardowy zakres od 0 do 255.

Przepływ pracy animacji Flutter

Przebieg animacji jest następujący -

  • Zdefiniuj i uruchom kontroler animacji w initState StatefulWidget.

AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = Tween<double>(begin: 0, end: 300).animate(controller); 
controller.forward();
  • Dodaj odbiornik oparty na animacji, addListener, aby zmienić stan widżetu.

animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
   setState(() { 
      // The state that has changed here is the animation object’s value. 
   }); 
});
  • W celu pominięcia tego procesu można użyć wbudowanych widżetów, AnimatedWidget i AnimatedBuilder. Oba widżety akceptują obiekt Animacja i pobierają aktualne wartości wymagane dla animacji.

  • Uzyskaj wartości animacji podczas procesu tworzenia widgetu, a następnie zastosuj je do szerokości, wysokości lub dowolnej odpowiedniej właściwości zamiast oryginalnej wartości.

child: Container( 
   height: animation.value, 
   width: animation.value, 
   child: <Widget>, 
)

Działająca aplikacja

Napiszmy prostą aplikację opartą na animacji, aby zrozumieć koncepcję animacji we frameworku Flutter.

  • Utwórz nową aplikację Flutter w Android Studio, product_animation_app.

  • Skopiuj folder zasobów z product_nav_app do product_animation_app i dodaj zasoby w pliku pubspec.yaml.

flutter: 
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Usuń domyślny kod startowy (main.dart).

  • Dodaj import i podstawową funkcję główną.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());
  • Utwórz widżet MyApp pochodzący z StatefulWidgtet.

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
}
  • Utwórz widżet _MyAppState i zaimplementuj initState i usuń oprócz domyślnej metody kompilacji.

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { 
   Animation<double> animation; 
   AnimationController controller; 
   @override void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this
      ); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose();
   }
}

Tutaj,

  • W metodzie initState utworzyliśmy obiekt kontrolera animacji (kontroler), obiekt animacji (animacja) i uruchomiliśmy animację za pomocą controller.forward.

  • W metodzie dispose usunęliśmy obiekt kontrolera animacji (kontroler).

  • W metodzie build wyślij animację do widżetu MyHomePage za pomocą konstruktora. Teraz widżet MyHomePage może używać obiektu animacji do animowania swojej zawartości.

  • Teraz dodaj widżet ProductBox

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image})
      : super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row( 
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.name, style: 
                                 TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.description), 
                                 Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      ); 
   }
}
  • Utwórz nowy widżet, MyAnimatedWidget, aby wykonać prostą animację zanikania za pomocą krycia.

class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
      
   final Widget child; 
   final Animation<double> animation; 
   
   Widget build(BuildContext context) => Center( 
   child: AnimatedBuilder(
      animation: animation, 
      builder: (context, child) => Container( 
         child: Opacity(opacity: animation.value, child: child), 
      ), 
      child: child), 
   ); 
}
  • Tutaj użyliśmy AniatedBuilder do wykonania naszej animacji. AnimatedBuilder to widżet, który buduje swoją zawartość podczas tworzenia animacji w tym samym czasie. Akceptuje obiekt animacji, aby uzyskać aktualną wartość animacji. Użyliśmy wartości animacji, animation.value, aby ustawić krycie widżetu podrzędnego. W efekcie widget będzie animował widget podrzędny przy użyciu koncepcji krycia.

  • Na koniec utwórz widżet MyHomePage i użyj obiektu animacji do animacji dowolnej jego zawartości.

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title, this.animation}) : super(key: key); 
   
   final String title; 
   final Animation<double> 
   animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")),body: ListView(
            shrinkWrap: true,
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), opacity: animation
               ), 
               MyAnimatedWidget(child: ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), animation: animation), 
               ProductBox(
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ),
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ),
            ],
         )
      );
   }
}

W tym przypadku użyliśmy FadeAnimation i MyAnimationWidget do animacji pierwszych dwóch elementów na liście. FadeAnimation to wbudowana klasa animacji, której użyliśmy do animowania jej elementu podrzędnego przy użyciu koncepcji krycia.

  • Kompletny kod wygląda następująco -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
} 
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
   Animation<double> animation; 
   AnimationController controller; 
   
   @override 
   void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,) 
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose(); 
   } 
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title, this.animation}): super(key: key);
   final String title; 
   final Animation<double> animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), 
                  opacity: animation
               ), 
               MyAnimatedWidget(
                  child: ProductBox( 
                     name: "Pixel", 
                     description: "Pixel is the most featureful phone ever", 
                     price: 800, 
                     image: "pixel.png"
                  ), 
                  animation: animation
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet",
                  description: "Tablet is the most useful device ever for meeting",
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ], 
         )
      ); 
   } 
} 
class ProductBox extends StatelessWidget { 
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded(
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ), 
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  ) 
               ]
            )
         )
      ); 
   } 
}
class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
   final Widget child; 
   final Animation<double> animation; 
 
   Widget build(BuildContext context) => Center( 
      child: AnimatedBuilder(
         animation: animation, 
         builder: (context, child) => Container( 
            child: Opacity(opacity: animation.value, child: child), 
         ), 
         child: child
      ), 
   ); 
}
  • Skompiluj i uruchom aplikację, aby zobaczyć wyniki. Wstępna i ostateczna wersja aplikacji wygląda następująco -

Flutter zapewnia ogólną strukturę dostępu do funkcji specyficznych dla platformy. Umożliwia to deweloperowi rozszerzenie funkcjonalności frameworka Flutter przy użyciu kodu specyficznego dla platformy. Funkcje specyficzne dla platformy, takie jak aparat, poziom naładowania baterii, przeglądarka itp., Są łatwo dostępne za pośrednictwem frameworka.

Ogólną ideą dostępu do kodu specyficznego dla platformy jest prosty protokół przesyłania wiadomości. Kod Flutter, klient i kod platformy oraz host są powiązane ze wspólnym kanałem wiadomości. Klient wysyła wiadomość do hosta za pośrednictwem kanału wiadomości. Host nasłuchuje na kanale wiadomości, odbiera wiadomość i wykonuje niezbędne funkcje, a na koniec zwraca wynik do klienta za pośrednictwem kanału wiadomości.

Architektura kodu specyficzna dla platformy jest pokazana na schemacie blokowym podanym poniżej -

Protokół przesyłania wiadomości wykorzystuje standardowy kodek wiadomości (klasa StandardMessageCodec), który obsługuje serializację binarną wartości podobnych do JSON, takich jak liczby, ciągi znaków, wartości logiczne itp. Serializacja i deserializacja działa w sposób przejrzysty między klientem a hostem.

Napiszmy prostą aplikację do otwierania przeglądarki za pomocą Android SDK i zrozummy, jak to zrobić

  • Utwórz nową aplikację Flutter w Android Studio, flutter_browser_app

  • Zastąp kod main.dart poniższym kodem -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Flutter Demo Home Page'),
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: null, 
            ), 
         ), 
      ); 
   }
}
  • Tutaj utworzyliśmy nowy przycisk do otwierania przeglądarki i ustawiania jej metody onPressed na null.

  • Teraz zaimportuj następujące pakiety -

import 'dart:async'; 
import 'package:flutter/services.dart';
  • Tutaj services.dart obejmują funkcję wywoływania kodu specyficznego dla platformy.

  • Utwórz nowy kanał wiadomości w widżecie MyHomePage.

static const platform = const 
MethodChannel('flutterapp.tutorialspoint.com/browser');
  • Napisz metodę _openBrowser, aby wywołać metodę specyficzną dla platformy, metodę openBrowser za pośrednictwem kanału komunikatów.

Future<void> _openBrowser() async { 
   try {
      final int result = await platform.invokeMethod(
         'openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         }
      ); 
   } 
   on PlatformException catch (e) { 
      // Unable to open the browser 
      print(e); 
   }
}

Tutaj użyliśmy platform.invokeMethod do wywołania openBrowser (wyjaśnione w kolejnych krokach). openBrowser ma argument, url, aby otworzyć określony adres URL.

  • Zmień wartość właściwości onPressedButton RaisedButton z null na _openBrowser.

onPressed: _openBrowser,
  • Otwórz plik MainActivity.java (w folderze Androida) i zaimportuj wymaganą bibliotekę -

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant;
  • Napisz metodę, otwórz przeglądarkę, aby otworzyć przeglądarkę

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = this; 
   if (activity == null) { 
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground 
      activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • Teraz ustaw nazwę kanału w klasie MainActivity -

private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser";
  • Napisz specyficzny dla Androida kod, aby ustawić obsługę wiadomości w metodzie onCreate -

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( 
   new MethodCallHandler() { 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("openBrowser")) {
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
});

Tutaj utworzyliśmy kanał komunikatów przy użyciu klasy MethodChannel i użyliśmy klasy MethodCallHandler do obsługi komunikatu. onMethodCall jest właściwą metodą odpowiedzialną za wywołanie prawidłowego kodu specyficznego dla platformy poprzez sprawdzenie wiadomości. Metoda onMethodCall wyodrębnia adres URL z wiadomości, a następnie wywołuje openBrowser tylko wtedy, gdy wywołanie metody to openBrowser. W przeciwnym razie zwraca metodę notImplemented.

Pełny kod źródłowy aplikacji jest następujący -

main.dart

MainActivity.java

package com.tutorialspoint.flutterapp.flutter_browser_app; 

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant; 

public class MainActivity extends FlutterActivity { 
   private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser"; 
   @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      GeneratedPluginRegistrant.registerWith(this); 
      new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
         new MethodCallHandler() {
            @Override 
            public void onMethodCall(MethodCall call, Result result) {
               String url = call.argument("url"); 
               if (call.method.equals("openBrowser")) { 
                  openBrowser(call, result, url); 
               } else { 
                  result.notImplemented(); 
               }
            }
         }
      ); 
   }
   private void openBrowser(MethodCall call, Result result, String url) {
      Activity activity = this; if (activity == null) {
         result.error(
            "ACTIVITY_NOT_AVAILABLE", "Browser cannot be opened without foreground activity", null
         ); 
         return; 
      } 
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   }
}

main.dart

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'package:flutter/services.dart'; 

void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget {
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   static const platform = const MethodChannel('flutterapp.tutorialspoint.com/browser'); 
   Future<void> _openBrowser() async {
      try {
         final int result = await platform.invokeMethod('openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         });
      }
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      } 
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: _openBrowser, 
            ), 
         ),
      );
   }
}

Uruchom aplikację i kliknij przycisk Otwórz przeglądarkę, a zobaczysz, że przeglądarka jest uruchomiona. Aplikacja Browser - Strona główna jest pokazana na zrzucie ekranu tutaj -

Dostęp do kodu specyficznego dla iOS jest podobny do tego na platformie Android, z tym wyjątkiem, że używa języków specyficznych dla iOS - Objective-C lub Swift i iOS SDK. W przeciwnym razie koncepcja jest taka sama jak w przypadku platformy Android.

Napiszmy również tę samą aplikację, co w poprzednim rozdziale na platformę iOS.

  • Stwórzmy nową aplikację w Android Studio (macOS), flutter_browser_ios_app

  • Wykonaj kroki 2–6, jak w poprzednim rozdziale.

  • Uruchom XCode i kliknij File → Open

  • Wybierz projekt xcode w katalogu ios naszego projektu flutter.

  • Otwórz AppDelegate.m pod Runner → Runner path. Zawiera następujący kod -

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      // [GeneratedPluginRegistrant registerWithRegistry:self];
      // Override point for customization after application launch.
      return [super application:application didFinishLaunchingWithOptions:launchOptions];
   } 
@end
  • Dodaliśmy metodę openBrowser do otwierania przeglądarki z określonym adresem URL. Akceptuje pojedynczy argument, url.

- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
}
  • W metodzie didFinishLaunchingWithOptions znajdź kontroler i ustaw go w zmiennej kontrolera.

FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
  • W metodzie didFinishLaunchingWithOptions ustaw kanał przeglądarki jako flutterapp.tutorialspoint.com/browse -

FlutterMethodChannel* browserChannel = [
   FlutterMethodChannel methodChannelWithName:
   @"flutterapp.tutorialspoint.com/browser" binaryMessenger:controller];
  • Utwórz zmienną, słabySelf i ustaw aktualną klasę -

__weak typeof(self) weakSelf = self;
  • Teraz zaimplementuj setMethodCallHandler. Wywołaj openBrowser, dopasowując call.method. Uzyskaj adres URL, wywołując call.arguments i przekaż go podczas wywoływania openBrowser.

[browserChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
   if ([@"openBrowser" isEqualToString:call.method]) { 
      NSString *url = call.arguments[@"url"];   
      [weakSelf openBrowser:url]; 
   } else { result(FlutterMethodNotImplemented); } 
}];
  • Kompletny kod wygląda następująco -

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application 
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
   // custom code starts 
   FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; 
   FlutterMethodChannel* browserChannel = [
      FlutterMethodChannel methodChannelWithName:
      @"flutterapp.tutorialspoint.com /browser" binaryMessenger:controller]; 
   
   __weak typeof(self) weakSelf = self; 
   [browserChannel setMethodCallHandler:^(
      FlutterMethodCall* call, FlutterResult result) { 
      
      if ([@"openBrowser" isEqualToString:call.method]) { 
         NSString *url = call.arguments[@"url"];
         [weakSelf openBrowser:url]; 
      } else { result(FlutterMethodNotImplemented); } 
   }]; 
   // custom code ends 
   [GeneratedPluginRegistrant registerWithRegistry:self]; 
   
   // Override point for customization after application launch. 
   return [super application:application didFinishLaunchingWithOptions:launchOptions]; 
}
- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
} 
@end
  • Otwórz ustawienia projektu.

  • Iść do Capabilities i włącz Background Modes.

  • Dodaj *Background fetch i Remote Notification**.

  • Teraz uruchom aplikację. Działa podobnie do wersji Androida, ale przeglądarka Safari zostanie otwarta zamiast chrome.

Dart organizuje i udostępnia zestaw funkcji za pośrednictwem pakietu. Pakiet Dart to po prostu współdzielone biblioteki lub moduły. Ogólnie rzecz biorąc, Pakiet Dart jest taki sam jak w aplikacji Dart, z wyjątkiem tego, że pakiet Dart nie ma punktu wejścia do aplikacji, main.

Ogólna struktura pakietu (rozważ pakiet demonstracyjny, my_demo_package) jest następująca -

  • lib/src/* - Prywatne pliki z kodem Dart.

  • lib/my_demo_package.dart- Główny plik kodu Darta. Można go zaimportować do aplikacji jako -

import 'package:my_demo_package/my_demo_package.dart'
  • Inny plik kodu prywatnego można wyeksportować do głównego pliku kodu (my_demo_package.dart), w razie potrzeby, jak pokazano poniżej -

export src/my_private_code.dart
  • lib/*- Dowolna liczba plików z kodem Dart ułożonych w dowolnej niestandardowej strukturze folderów. Dostęp do kodu można uzyskać jako,

import 'package:my_demo_package/custom_folder/custom_file.dart'
  • pubspec.yaml - Specyfikacja projektu taka sama jak w aplikacji,

Wszystkie pliki z kodem Dart w Pakiecie są po prostu klasami Dart i nie ma żadnych specjalnych wymagań, aby kod Dart zawierał go w pakiecie.

Rodzaje paczek

Ponieważ pakiety Dart są w zasadzie niewielką kolekcją podobnych funkcji, można je podzielić na kategorie na podstawie ich funkcjonalności.

Pakiet Dart

Ogólny kod Dart, którego można używać zarówno w środowisku internetowym, jak i mobilnym. Na przykład, english_words jest jednym z takich pakietów, który zawiera około 5000 słów i ma podstawowe funkcje użytkowe, takie jak rzeczowniki (lista rzeczowników w języku angielskim), sylaby (określ liczbę sylab w słowie.

Pakiet Flutter

Ogólny kod Dart, który zależy od frameworka Flutter i może być używany tylko w środowisku mobilnym. Na przykład fluro to niestandardowy router do fluttera. To zależy od frameworka Flutter.

Wtyczka Flutter

Ogólny kod Dart, który zależy od frameworka Flutter, a także kodu platformy (Android SDK lub iOS SDK). Na przykład kamera to wtyczka do interakcji z kamerą urządzenia. Zależy to od frameworka Flutter, a także od podstaw, aby uzyskać dostęp do kamery.

Korzystanie z pakietu do rzutek

Pakiety Dart są hostowane i publikowane na serwerze rzeczywistym, https://pub.dartlang.org.Flutter zapewnia również proste narzędzie, pub do zarządzania pakietami Dart w aplikacji. Kroki potrzebne do użycia jako pakietu są następujące -

  • Dołącz nazwę pakietu i wymaganą wersję do pliku pubspec.yaml, jak pokazano poniżej -

dependencies: english_words: ^3.1.5
  • Najnowszy numer wersji można znaleźć, sprawdzając serwer online.

  • Zainstaluj pakiet w aplikacji za pomocą następującego polecenia -

flutter packages get
  • Podczas programowania w Android Studio, Android Studio wykrywa wszelkie zmiany w pubspec.yaml i wyświetla deweloperowi alert dotyczący pakietu Android Studio, jak pokazano poniżej -

  • Pakiety Dart można instalować lub aktualizować w Android Studio za pomocą opcji menu.

  • Zaimportuj potrzebny plik za pomocą polecenia pokazanego poniżej i rozpocznij pracę -

import 'package:english_words/english_words.dart';
  • Skorzystaj z dowolnej metody dostępnej w pakiecie,

nouns.take(50).forEach(print);
  • Tutaj użyliśmy funkcji rzeczowników, aby pobrać i wydrukować 50 pierwszych słów.

Opracuj pakiet wtyczek Flutter

Tworzenie wtyczki Flutter jest podobne do tworzenia aplikacji Dart lub pakietu Dart. Jedynym wyjątkiem jest to, że wtyczka będzie używać interfejsu API systemu (Android lub iOS), aby uzyskać wymaganą funkcjonalność specyficzną dla platformy.

Ponieważ nauczyliśmy się już, jak uzyskać dostęp do kodu platformy w poprzednich rozdziałach, opracujmy prostą wtyczkę my_browser, aby zrozumieć proces tworzenia wtyczki. Funkcjonalność wtyczki my_browser polega na umożliwieniu aplikacji otwarcia danej strony internetowej w przeglądarce specyficznej dla platformy.

  • Uruchom Android Studio.

  • Kliknij File → New Flutter Project i wybierz opcję Flutter Plugin.

  • Możesz zobaczyć okno wyboru wtyczki Flutter, jak pokazano tutaj -

  • Wpisz my_browser jako nazwę projektu i kliknij Dalej.

  • Wprowadź nazwę wtyczki i inne szczegóły w oknie, jak pokazano tutaj -

  • Wprowadź domenę firmy, flutterplugins.tutorialspoint.com w oknie pokazanym poniżej, a następnie kliknij Finish. Wygeneruje kod startowy do opracowania naszej nowej wtyczki.

  • Otwórz plik my_browser.dart i napisz metodę, openBrowser, aby wywołać metodę openBrowser specyficzną dla platformy.

Future<void> openBrowser(String urlString) async { 
   try {
      final int result = await _channel.invokeMethod(
         'openBrowser', <String, String>{ 'url': urlString }
      );
   }
   on PlatformException catch (e) { 
      // Unable to open the browser print(e); 
   } 
}
  • Otwórz plik MyBrowserPlugin.java i zaimportuj następujące klasy -

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle;
  • Tutaj musimy zaimportować bibliotekę wymaganą do otwarcia przeglądarki z Androida.

  • Dodaj nową zmienną prywatną mRegistrar typu Registrar w klasie MyBrowserPlugin.

private final Registrar mRegistrar;
  • Tutaj Registrar jest używany do uzyskania informacji o kontekście kodu wywołującego.

  • Dodaj konstruktora, aby ustawić Registrar w klasie MyBrowserPlugin.

private MyBrowserPlugin(Registrar registrar) { 
   this.mRegistrar = registrar; 
}
  • Zmień registerWith, aby uwzględnić nasz nowy konstruktor w klasie MyBrowserPlugin.

public static void registerWith(Registrar registrar) { 
   final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_browser"); 
   MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
   channel.setMethodCallHandler(instance); 
}
  • Zmień onMethodCall tak, aby zawierał metodę openBrowser w klasie MyBrowserPlugin.

@Override 
public void onMethodCall(MethodCall call, Result result) { 
   String url = call.argument("url");
   if (call.method.equals("getPlatformVersion")) { 
      result.success("Android " + android.os.Build.VERSION.RELEASE); 
   } 
   else if (call.method.equals("openBrowser")) { 
      openBrowser(call, result, url); 
   } else { 
      result.notImplemented(); 
   } 
}
  • Napisz metodę openBrowser specyficzną dla platformy, aby uzyskać dostęp do przeglądarki w klasie MyBrowserPlugin.

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = mRegistrar.activity(); 
   if (activity == null) {
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • Pełny kod źródłowy wtyczki my_browser jest następujący -

my_browser.dart

import 'dart:async'; 
import 'package:flutter/services.dart'; 

class MyBrowser {
   static const MethodChannel _channel = const MethodChannel('my_browser'); 
   static Future<String> get platformVersion async { 
      final String version = await _channel.invokeMethod('getPlatformVersion'); return version; 
   } 
   Future<void> openBrowser(String urlString) async { 
      try {
         final int result = await _channel.invokeMethod(
            'openBrowser', <String, String>{'url': urlString}); 
      } 
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      }
   }
}

MyBrowserPlugin.java

package com.tutorialspoint.flutterplugins.my_browser; 

import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugin.common.PluginRegistry.Registrar; 
import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

/** MyBrowserPlugin */ 
public class MyBrowserPlugin implements MethodCallHandler {
   private final Registrar mRegistrar; 
   private MyBrowserPlugin(Registrar registrar) { 
      this.mRegistrar = registrar; 
   } 
   /** Plugin registration. */
   public static void registerWith(Registrar registrar) {
      final MethodChannel channel = new MethodChannel(
         registrar.messenger(), "my_browser"); 
      MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
      channel.setMethodCallHandler(instance); 
   } 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("getPlatformVersion")) { 
         result.success("Android " + android.os.Build.VERSION.RELEASE); 
      } 
      else if (call.method.equals("openBrowser")) { 
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
   private void openBrowser(MethodCall call, Result result, String url) { 
      Activity activity = mRegistrar.activity(); 
      if (activity == null) {
         result.error("ACTIVITY_NOT_AVAILABLE",
            "Browser cannot be opened without foreground activity", null); 
         return; 
      }
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   } 
}
  • Utwórz nowy projekt, my_browser_plugin_test, aby przetestować naszą nowo utworzoną wtyczkę.

  • Otwórz pubspec.yaml i ustaw my_browser jako zależność od wtyczki.

dependencies: 
   flutter: 
      sdk: flutter 
   my_browser: 
      path: ../my_browser
  • Studio Android ostrzeże, że plik pubspec.yaml został zaktualizowany, jak pokazano w alercie dotyczącym pakietu Android Studio podanym poniżej -

  • Kliknij opcję Pobierz zależności. Studio Android pobierze pakiet z Internetu i odpowiednio skonfiguruje go dla aplikacji.

  • Otwórz main.dart i dołącz wtyczkę my_browser, jak poniżej -

import 'package:my_browser/my_browser.dart';
  • Wywołaj funkcję openBrowser z wtyczki my_browser, jak pokazano poniżej -

onPressed: () => MyBrowser().openBrowser("https://flutter.dev"),
  • Pełny kod pliku main.dart wygląda następująco -

import 'package:flutter/material.dart'; 
import 'package:my_browser/my_browser.dart'; 

void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      );,
   }
} 
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton(
               child: Text('Open Browser'), 
               onPressed: () => MyBrowser().openBrowser("https://flutter.dev"), 
            ),
         ), 
      ); 
   }
}
  • Uruchom aplikację i kliknij przycisk Otwórz przeglądarkę i zobacz, czy przeglądarka jest uruchomiona. Możesz zobaczyć aplikację przeglądarki - Strona główna, jak pokazano na zrzucie ekranu pokazanym poniżej -

Możesz zobaczyć aplikację przeglądarki - ekran przeglądarki, jak pokazano na zrzucie ekranu pokazanym poniżej -

  • Print
  •  Dodaj notatki
  •  Dodaj stronę do ulubionych
  •  Zgłoś błąd
  •  Suggestions

Zapisz Zamknij