Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels
"Träumen Flutter-Apps von plattformbewussten Widgets?"
Bei der Entwicklung von Anwendungen auf Flutter mit einem nativen Design für iOS und Android stieß ich auf die Tatsache, dass ich eine Reihe von Bedingungen schreiben musste, um die Plattform zu überprüfen, auf der der Code ausgeführt wird, während ich zwei ähnliche UI-Implementierungen durchführte. Das hat mir nicht gefallen und ich bin froh, dass ich auf einen Artikel gestoßen bin, der mir geholfen hat, mein Problem zu lösen.
Über den Autor: Swav Kulinski - Leitender Android-Entwickler bei The App Business, Flutter GDE.
Als nächstes werden wir im Namen des Autors sprechen.
Flutter ist eine plattformübergreifende Lösung für die Entwicklung mobiler Anwendungen, die absolute Freiheit bei der Erstellung einer Benutzeroberfläche unabhängig von der Plattform verspricht. Dies wird durch die Tatsache erreicht, dass das Framework seine eigene Rendering-Engine zum Zeichnen von Widgets verwendet.
Das Problem bei vielen plattformübergreifenden Lösungen ist, dass sie auf iPhone und Android gleich aussehen. Aber was ist mit Unternehmen, die das Erscheinungsbild der Plattform beibehalten müssen? Wer muss Material Design für Android und Human Interface für iOS verwenden? Für solche Unternehmen ist Flutter geeignet und mit Paketen ausgestattet, die eine Reihe von benutzerdefinierten Widgets für iOS und Android enthalten, Cupertino und Material.

Flutter ist plattformübergreifend, aber wenn es um die Layout-Benutzeroberfläche geht, die für jede Plattform nativ aussehen sollte, ist dies nicht ganz richtig. Wir müssen zwei ähnliche Layout-Implementierungen durchführen. Dies liegt daran, dass sich die CupertinoNavigationBar beispielsweise für iOS in CupertinoPageScaffold und in Android in der AppBar in Scaffold befinden muss. Diese Funktion reduziert den Vorteil der plattformübergreifenden Ausführung in Flutter, da Sie für jede Plattform Ihren eigenen Code für das Layout schreiben müssen.
Ich möchte einen Ansatz vorschlagen, mit dem Sie abstrakte Schnittstellen erstellen und das Erscheinungsbild und Verhalten der Anwendung je nach Plattform anpassen können.
Betrachten Sie die folgenden Konstruktoren für zwei Widgets, die eine obere Anwendungsleiste bereitstellen:
CupertinoNavigationBar ({ this.leading, this.middle, })
und
AppBar ({ this.leading, this.title })
Beide oben genannten Widgets spielen dieselbe Rolle und sind das oberste Bedienfeld in der Anwendung im Stil von Cupertino und Material. Dennoch erfordern sie eine andere Eingabe. Es wird eine Lösung benötigt, die von der Erstellung bestimmter Widgets abweicht und gleichzeitig die Implementierung abhängig von der Plattform ermöglicht. Wir werden die gute alte Fabrikmethode anwenden.
import 'package:flutter/material.dart'; import 'dart:io' show Platform; abstract class PlatformWidget<I extends Widget, A extends Widget> extends StatelessWidget { @override Widget build(BuildContext context) { if (Platform.isAndroid) { return createAndroidWidget(context); } else if (Platform.isIOS) { return createIosWidget(context); } // platform not supported returns an empty widget return Container(); } I createIosWidget(BuildContext context); A createAndroidWidget(BuildContext context); }
Tatsächlich handelt es sich bei der obigen Klasse um eine plattformabhängige Widget-Factory, die bei ihrer Implementierung einen benutzerdefinierten Konstruktor (oder mehrere benannte Konstruktoren) bereitstellen kann, der die Anforderungen beider spezifischer Klassen unterstützt.
Ich habe Generika ausgewählt, um bestimmte Klassen zurückzugeben, da das übergeordnete Widget manchmal einen bestimmten Typ benötigt, der vom untergeordneten Widget zurückgegeben werden muss.
Jetzt können wir unser erstes Widget implementieren.
class PlatformAppBar extends PlatformWidget<CupertinoNavigationBar, AppBar> { final Widget leading; final Widget title; PlatformAppBar({ this.leading, this.title, }); @override AppBar createAndroidWidget(BuildContext context) { return AppBar( leading: leading, title: title, ); } @override CupertinoNavigationBar createIosWidget(BuildContext context) { return CupertinoNavigationBar( leading: leading, middle: title, ); } }
Ziemlich einfach, oder? Bitte beachten Sie, dass wir die volle Kontrolle über den Inhalt von Widgets im Anwendungsbereich haben.
Angenommen, wir haben Scaffold und Button implementiert.
class PlatformScaffoldWidget extends PlatformWidget<CupertinoPageScaffold,Scaffold> { ... } class PlatformButton extends PlatformWidget<CupertinoButton,FlatButton> { ... }
Jetzt können wir unsere plattformorientierten Widgets verwenden und wiederverwenden.
Widget build(BuildContext context) { return PlatformScaffoldWidget( appBar: PlatformAppBarWidget( leading: PlatformButton( child: Icon(Icons.ic_arrow_back), onClick: () => _handleBack() ), title: Text("I love my Platform"), ), content: ... ); }
Fertig! Der obige Code zeigt auf beiden Plattformen eine plattformorientierte Anwendungsleiste an, und unser PlatformScaffoldWidget kann problemlos im Rest der Anwendung wiederverwendet werden.
Der Code kann auf dem
Github angezeigt werden.