如何在Flutter中将AppBar放在单独的文件中,同时仍显示小部件?

Xav*_*ito 2 mobile android appbar dart flutter

我目前正在开发一个Flutter应用程序,推荐该地区的餐馆。但是,我陷入了困境。

为了组织和整洁,我希望我的应用程序的AppBar代码与每个屏幕的代码分开。因此,我将KainAppBar.dart构建为AppBar代码。如图所示:

import 'package:flutter/material.dart';
import 'package:gradient_app_bar/gradient_app_bar.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

GoogleSignIn _googleSignIn = GoogleSignIn(
  signInOption: SignInOption.standard,
);

class KainAppBar extends StatelessWidget {
  final String title;

  KainAppBar(this.title);

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: new GradientAppBar(
      centerTitle: true,
      title: new Text('Kain',
      style: TextStyle(
        fontFamily: 'Quiapo', fontSize: 36.0, fontWeight: FontWeight.w600
      )),
      backgroundColorStart: Colors.red[400],
      backgroundColorEnd: Colors.red[900],
    ),
    drawer: new Drawer(
      child: ListView(
        children: <Widget>[
          new UserAccountsDrawerHeader(
            decoration: BoxDecoration(
              color: Colors.red[800],
            ),
            accountName: new Text('Guest'),
            accountEmail: new Text('guestemail@email.com'),
            currentAccountPicture: new CircleAvatar(
              backgroundImage: new NetworkImage('https://avatarfiles.alphacoders.com/848/84855.jpg'),
            ),
          ),
          new ListTile(
            title: new Text('Restaurants'),
            leading: Icon(Icons.restaurant_menu),
            onTap: (){
              Navigator.of(context).pop();
              Navigator.of(context).pushNamed('/restaurant_screen');
            },
          ),
          new ListTile(
            title: new Text('Nearby'),
            leading: Icon(Icons.near_me),
            onTap: (){
              Navigator.of(context).pop();
              Navigator.of(context).pushNamed('/nearby_screen');
            },
          ),
          new ListTile(
            title: new Text('Request Restaurant'),
            leading: Icon(Icons.library_add),
            onTap: (){
              Navigator.of(context).pop();
              Navigator.of(context).pushNamed('/request_screen');
            },
          ),
          new ListTile(
            title: new Text('Settings'),
            leading: Icon(Icons.settings),
            onTap: (){},
          ),
          new ListTile(
            title: new Text('About'),
            leading: Icon(Icons.info_outline),
            onTap: (){},
          ),
          new ListTile(
            title: new Text('Logout'),
            leading: Icon(Icons.power_settings_new),
            onTap: (){
                  _googleSignIn.disconnect();
              FirebaseAuth.instance.signOut().then((value) {
                    Navigator.of(context).pushReplacementNamed('/login');
                  }).catchError((e) {
                     print(e);
                  });
            },
          ),
        ],
      ),
    ),
     body: new Column(
       crossAxisAlignment: CrossAxisAlignment.center,
       mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Container(
          padding: EdgeInsets.fromLTRB(50.0, 160.0, 50.0, 0.0),
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
            ],
          ),
        )
      ],
    ),

    );

  }
}
Run Code Online (Sandbox Code Playgroud)

对于某些屏幕,我可以毫无问题地声明它。这是home_screen.dart的代码:

    class HomeScreen extends StatefulWidget {
      @override
      HomeScreenState createState() {
        return HomeScreenState();
      }
    }

    class HomeScreenState extends State<HomeScreen>{
    @override
      noSuchMethod(Invocation invocation) {
        return super.noSuchMethod(invocation);
      }
    @override
    Widget build(BuildContext context){

      return new KainAppBar("Kain");

      }
    }
Run Code Online (Sandbox Code Playgroud)

但是,对于我的restaurant_screen.dart,我遇到了一个问题。对于上下文,restaurant_screen.dart所做的是通过带有三个选项(选项卡)的TabBar显示应用程序中包含的餐厅:餐厅列表,美食列表和历史记录。这意味着除了AppBar之外,还需要在其中包含TabBar。但是我不能将此TabBar放在KainAppBar.dart内,因为我只需要它显示在restaurant_screen.dart内即可

这是我在restaurant_screen.dart中的Widget的代码:

  @override
  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        GradientAppBar(
          title: KainAppBar("Kain"),
          bottom: new TabBar(
            labelColor: Colors.white,
            controller: tController,
            tabs: <Widget>[
              new Tab(text: 'List'),
              new Tab(text: 'Cuisine'),
              new Tab(text: 'Favorites'),
              ],
              ),
              ),
              TabBarView(
                controller: tController,
                children: <Widget>[
                  new firstpage.RestaurantList(),
                  new secondpage.CuisineList(),
                  new thirdpage.RestaurantFavorites(),
                  ],
              ),
      ],
    );
  }
Run Code Online (Sandbox Code Playgroud)

运行代码仅显示黑屏。有什么解决方法吗?

小智 16

您可以将 AppBar 包装到返回 AppBar 的函数中。

headerNav.dart

import 'package:flutter/material.dart';

AppBar headerNav({String title}){
  return AppBar(
    title: Text(title),
  );
}
Run Code Online (Sandbox Code Playgroud)

homePage.dart

import 'package:flutter/material.dart';
import 'package:myapp/components/headerNav.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: headerNav(text:'Home Page'),
      body: Container(
        child: Text('Home'),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*los 12

实现PreferredSizeWidget并覆盖这样的方法(kToolbarHeight来自 material.dart是 使用的默认高度AppBar)。您也可以根据需要设置高度。

class NavBar extends StatelessWidget implements PreferredSizeWidget {
  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: Text('Hello'),
    );
  }

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
Run Code Online (Sandbox Code Playgroud)

  • kToolbarHeight 确实是 MaterialApp 的顶级常量 https://api.flutter.dev/flutter/material/kToolbarHeight-constant.html (4认同)

ck_*_*_12 10

这是另一种解决方法。通过执行此操作,可以根据需要自定义此应用栏。这样,如果继续使用该样式,则不必在每个页面上都重新创建它。您只需创建一次,然后在任何小部件中调用它。

import 'package:flutter/material.dart';

class BaseAppBar extends StatelessWidget implements PreferredSizeWidget {
  final Color backgroundColor = Colors.red;
  final Text title;
  final AppBar appBar;
  final List<Widget> widgets;

  /// you can add more fields that meet your needs

  const BaseAppBar({Key key, this.title, this.appBar, this.widgets})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: title,
      backgroundColor: backgroundColor,
      actions: widgets,
    );
  }

  @override
  Size get preferredSize => new Size.fromHeight(appBar.preferredSize.height);
}

Run Code Online (Sandbox Code Playgroud)

在所需页面内实施

@override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: BaseAppBar(
          title: Text('title'),
          appBar: AppBar(),
          widgets: <Widget>[Icon(Icons.more_vert)],
        ),
        body: Container());
  }
Run Code Online (Sandbox Code Playgroud)

  • 这对我不起作用,我添加了 getter 并实现了 PreferredSizeWidget,但仍然收到错误 The getter 'preferredSize' was called on null。接收者:null 尝试调用:preferredSize (4认同)
  • 最终变量“appBar”必须初始化。 (3认同)
  • 您可以使用 kToolbarHeight 来代替 AppBar 实例来获取其高度: @override Size get PreferredSize =&gt; new Size.fromHeight(kToolbarHeight); (2认同)

abs*_*sin 9

让我们有一个widget.dart像这样:

import 'package:flutter/material.dart';

class ReusableWidgets {
  static getAppBar(String title) {
    return AppBar(
      title: Text(title),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

让我们继续使用此类来进入appbar所有屏幕,如下所示:

import 'package:filter_chip/widgets.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: new ReusableWidgets().getAppBar('Hello World'),
        body:  Text(
            'Flutter Demo Home Page'), 
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Nea*_*arl 8

要定义您自己的AppBar,您需要preferredSizePreferredSizeWidget类中实现。但如果您想保留默认大小,您可以AppBar通过创建内部实例并引用其大小来模仿原始大小,如下所示:

class MyFancyAppBar extends StatelessWidget implements PreferredSizeWidget {
  final String title;

  const MyFancyAppBar({Key? key, required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AppBar(...);
  }

  static final _appBar = AppBar();
  @override
  Size get preferredSize => _appBar.preferredSize;
}
Run Code Online (Sandbox Code Playgroud)

现场演示