Flattern: AppBar & SliverAppBar aufpumpen

Flutter verwendet die bekannte AppBar , um eine Symbolleiste zu erstellen. Wenn wir jedoch eine dynamische Symbolleiste benötigen, die beim Wischen Inhalte anzeigt, verwenden wir das hervorragende SliverAppBar- Widget.


Mit beiden Widgets können Sie die Anwendung etwas schöner gestalten, was in Flutter zweifellos sehr einfach ist.


Ich habe auf StackOverflow und in Facebook-Gruppen viele Fragen dazu gesehen, wie Sie AppBar und SliverAppBar in Bezug auf Verhalten oder Design ändern können.


Schauen wir uns zwei Aufgaben an.


Aufgabe 1


Wir möchten eine AppBar erstellen, die nicht am oberen Bildschirmrand angeschraubt ist, aber nicht wie gewohnt . Wir möchten eine Schublade ( Seitenmenü ) hinzufügen, auf deren Öffnung die AppBar reagiert. Das war's: unsere eigene AppBar   mit den Dimensionen, die wir brauchen.


Das Problem ist, dass AppBar bekanntlich eine Standardgröße hat und wir diese nicht ändern können. Nachdem wir uns den Quellcode angesehen haben, sehen wir den AppBar- Parameter in Scaffold . Wir sehen, dass er ein Widget vom Typ PreferredSizeWidget akzeptiert. Jetzt schauen wir uns den AppBar- Quellcode an und stellen fest, dass dies nur StatefulWidget ist , das PreferredSizeWidget implementiert.



Der Punkt ist klein: Erstellen Sie einfach unser eigenes Widget, das PreferredSizeWidget implementiert.


Das wollen wir



Wie würden Sie dies tun, wenn Sie auf die Menüschaltfläche unserer AppBar klicken, wird ein Seitenmenü geöffnet.


Wir können dies auf zwei Arten tun:


Verwenden der AppBar


Auf diese Weise kann AppBar das Öffnen der Seitenleiste im Scaffold steuern.


class Sample1 extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( drawer: Drawer(), appBar: MyCustomAppBar( height: 150, ), body: Center( child: FlutterLogo( size: MediaQuery.of(context).size.width / 2, ), ), ), ); } } class MyCustomAppBar extends StatelessWidget implements PreferredSizeWidget { final double height; const MyCustomAppBar({ Key key, @required this.height, }) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ Container( color: Colors.grey[300], child: Padding( padding: EdgeInsets.all(30), child: AppBar( title: Container( color: Colors.white, child: TextField( decoration: InputDecoration( hintText: "Search", contentPadding: EdgeInsets.all(10), ), ), ), actions: [ IconButton( icon: Icon(Icons.verified_user), onPressed: () => null, ), ], ) , ), ), ], ); } @override Size get preferredSize => Size.fromHeight(height); } 

Verwenden eines benutzerdefinierten Widgets


Hier haben wir mehr Flexibilität und Sie können GlobalKey wie ScaffoldState oder InheritedWidget von Scaffold verwenden , um Zugriff auf die Statusmethoden zum Öffnen von Drawer zu erhalten .


 import 'package:flutter/material.dart'; class Sample1 extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( drawer: Drawer(), appBar: MyCustomAppBar( height: 150, ), body: Center( child: FlutterLogo( size: MediaQuery.of(context).size.width / 2, ), ), ), ); } } class MyCustomAppBar extends StatelessWidget implements PreferredSizeWidget { final double height; const MyCustomAppBar({ Key key, @required this.height, }) : super(key: key); @override Widget build(BuildContext context) { return Column( children: [ Container( color: Colors.grey[300], child: Padding( padding: EdgeInsets.all(30), child: Container( color: Colors.red, padding: EdgeInsets.all(5), child: Row(children: [ IconButton( icon: Icon(Icons.menu), onPressed: () { Scaffold.of(context).openDrawer(); }, ), Expanded( child: Container( color: Colors.white, child: TextField( decoration: InputDecoration( hintText: "Search", contentPadding: EdgeInsets.all(10), ), ), ), ), IconButton( icon: Icon(Icons.verified_user), onPressed: () => null, ), ]), ), ), ), ], ); } @override Size get preferredSize => Size.fromHeight(height); } 

Ergebnis



Einfach, richtig? Schauen wir uns die zweite Aufgabe für SliverAppBar an .


Aufgabe 2


Wie wir wissen, funktioniert SliverAppBar wie folgt:



Wir möchten die Karte in unsere SliverAppBar einbauen , wie in der folgenden Abbildung gezeigt.



Warten Sie, aber der Inhalt in der SliverAppBar ist beschnitten, sodass er nicht über das hinausgehen kann, was zu tun ist.



Sehen wir uns ohne Panik den Quellcode von SliverAppBar an. Überraschenderweise ist dies StatefulWidget , das SliverPersistentHeader verwendet. Das ist das ganze Geheimnis.


Wir werden unser eigenes SliverPersistentHeaderDelegate erstellen, um den SliverPersistentHeader zu verwenden .


 class Sample2 extends StatelessWidget { @override Widget build(BuildContext context) { return SafeArea( child: Material( child: CustomScrollView( slivers: [ SliverPersistentHeader( delegate: MySliverAppBar(expandedHeight: 200), pinned: true, ), SliverList( delegate: SliverChildBuilderDelegate( (_, index) => ListTile( title: Text("Index: $index"), ), ), ) ], ), ), ); } } class MySliverAppBar extends SliverPersistentHeaderDelegate { final double expandedHeight; MySliverAppBar({@required this.expandedHeight}); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Stack( fit: StackFit.expand, overflow: Overflow.visible, children: [ Image.network( "https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500", fit: BoxFit.cover, ), Center( child: Opacity( opacity: shrinkOffset / expandedHeight, child: Text( "MySliverAppBar", style: TextStyle( color: Colors.white, fontWeight: FontWeight.w700, fontSize: 23, ), ), ), ), Positioned( top: expandedHeight / 2 - shrinkOffset, left: MediaQuery.of(context).size.width / 4, child: Opacity( opacity: (1 - shrinkOffset / expandedHeight), child: Card( elevation: 10, child: SizedBox( height: expandedHeight, width: MediaQuery.of(context).size.width / 2, child: FlutterLogo(), ), ), ), ), ], ); } @override double get maxExtent => expandedHeight; @override double get minExtent => kToolbarHeight; @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true; } 

Ergebnis



Fertig, beide Aufgaben sind gelöst.


Beispiele finden Sie in diesem Repository .


Fazit


Oft verzweifeln wir, wenn wir keine Eigenschaften des Widgets finden, aber Sie müssen sich nur den Quellcode ansehen, um zu verstehen, wie es in Flutter implementiert ist, und so herausfinden, wie wir unsere eigenen Widgets implementieren können.

Source: https://habr.com/ru/post/de456054/


All Articles