在 Flutter 中展开应用栏以允许多行标题?

问题描述 投票:0回答:8

有谁知道如何根据此处显示的材料指南创建具有多行标题的应用程序栏?

https://material.io/design/components/app-bars-top.html#anatomy

有什么想法可以做到这一点吗?鉴于它是材料指南的一部分,它似乎应该很简单!值得指出的是,标题是用户定义的,因此我希望允许应用栏根据用户输入从单行扩展到多行(可能会施加限制)。

迈克

flutter flutter-layout
8个回答
11
投票

尚未实施。

但是,您可以通过使用专为

SliverAppBar
设计的
CustomScrollView
获得类似的结果。

请记住,这并不是最佳选择。因为它需要对图标和内容的大小进行硬编码。由于

FlexibleSpacebar
没有宽度限制。

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_project/materialSheet.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverMultilineAppBar(
            title: "Summer Trip to Tokyo and Kyoto",
            leading: IconButton(
              onPressed: () {},
              icon: Icon(Icons.menu),
            ),
            actions: <Widget>[
              IconButton(
                onPressed: () {},
                icon: Icon(Icons.search),
              ),
              IconButton(
                onPressed: () {},
                icon: Icon(Icons.more_vert),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class SliverMultilineAppBar extends StatelessWidget {
  final String title;
  final Widget leading;
  final List<Widget> actions;

  SliverMultilineAppBar({this.title, this.leading, this.actions});

  @override
  Widget build(BuildContext context) {
    final mediaQuery = MediaQuery.of(context);

    double availableWidth = mediaQuery.size.width - 160;
    if (actions != null) {
      availableWidth -= 32 * actions.length;
    }
    if (leading != null) {
      availableWidth -= 32;
    }
    return SliverAppBar(
      expandedHeight: 120.0,
      forceElevated: true,
      leading: leading,
      actions: actions,
      flexibleSpace: FlexibleSpaceBar(
        title: ConstrainedBox(
          constraints: BoxConstraints(
            maxWidth: availableWidth,
          ),
          child: Text(title, textScaleFactor: .8,),
        ),
      ),
    );
  }
}

8
投票

您可以使用富文本:

          SliverAppBar(
        flexibleSpace: FlexibleSpaceBar(
          background: Container(
            color: Colors.indigoAccent,
          ),
          title: RichText(
            text: TextSpan(children: [
              TextSpan(
                text: Constants.homePageTitle,
                style: textTheme.headline,
              ),
              TextSpan(text: "\n"),
              TextSpan(
                text: Constants.homePageSubtitle,
                style: textTheme.subtitle,
              )
            ]),
          ),
          titlePadding: EdgeInsets.only(left: 10, bottom: 20),
        ),
        floating: true,
        backgroundColor: Colors.greenAccent,
        expandedHeight: 150.0,
      ),

8
投票

尝试下面的代码。这将提供多行,您还可以在其中控制文本样式。 如果您不希望所有行都有不同的样式,请使用文本而不是 RichText。

             AppBar(
                title: RichText(
                  textAlign: TextAlign.center,
                  text: TextSpan(
                      text: "Developer Developer",
                      style: TextStyle(fontSize: 20),
                      children: <TextSpan>[
                        TextSpan(
                          text: '\nTrip List',
                          style: TextStyle(
                            fontSize: 16,
                          ),
                        ),
                      ]
                  ),
                ),
                backgroundColor: MissionGPSTheme.themeBlueColor
            ),


5
投票

AppBar 会让您接近这一点,但是您必须根据文本长度指示底部 PreferredSize 小部件的高度,这并不理想。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      backgroundColor: Colors.deepPurple,
      leading: IconButton(icon: Icon(Icons.menu), onPressed: () {}),
      actions: <Widget>[
        IconButton(icon: Icon(Icons.search), onPressed: () {}),
        IconButton(icon: Icon(Icons.more_vert), onPressed: () {}),
      ],
      bottom: PreferredSize(
        child: Padding(
          padding: const EdgeInsets.fromLTRB(80.0, 0.0, 80.0, 16.0),
          child: Text(
            "Summer Trip to Tokyo and Kyoto",
            style: TextStyle(
              color: Colors.white,
              fontSize: 24.0,
            ),
          ),
        ),
        preferredSize: Size(0.0, 80.0),
      ),
    ),
    body: Text("..."),
  );
}

4
投票

这段代码将创建一个自定义的

Scaffold
,其中
AppBar
支持接收无标题、有标题、有标题和副标题。如果您不提供标题,它将显示给定的文本(在示例中为应用程序的名称),而如果您设置了标题和副标题,它将使用具有适当材质的两行样式设计文字样式。

import 'package:flutter/material.dart';

class TwoLinesAppBarScaffold extends StatelessWidget {
  final Widget body;
  final String title;
  final String subtitle;

  TwoLinesAppBarScaffold({this.body, this.title = "QuitNow!", this.subtitle});

  @override
  Widget build(BuildContext context) {
    Widget widget;

    if (subtitle == null) {
      widget = Text(title);
    } else {
      widget = RichText(
        textAlign: TextAlign.start,
        text: TextSpan(
            text: title,
            style: TextStyle(
              fontSize: 20,
              fontWeight: FontWeight.w500,
            ),
            children: <TextSpan>[
              TextSpan(
                text: '\n$subtitle',
                style: TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                ),
              ),
            ]),
      );
    }

    return Scaffold(
        appBar: AppBar(
          title: widget,
        ),
        body: Center(child: body));
  }
}

2
投票

这可以通过将 AppBar 的“title”属性替换为“flexibleSpace”来实现:

  Scaffold(
    appBar: AppBar(
      flexibleSpace: Center(
        child: Column(
          children: [
            Text('Title Line One'),
            Text('Title Line Two'),
          ],
        ),
      ),
    ),
    body: body
  ),

如果由于高度导致溢出,只需用 PreferredSize 小部件包裹 AppBar 并将高度设置为比默认值更高的值:

  Scaffold(
    appBar: PreferredSize(
      preferredSize: Size.fromHeight(100),
      child: AppBar(...),
    ),
  ),

0
投票

你可以在你的应用栏中尝试这个

AppBar(
        backgroundColor: Colors.green,
        title: Text(
          softWrap: true,
          maxLines: null,
         'This is a big text in appbar')
        )

-1
投票

找到了一些使用 textPainter 的解决方案,根据其样式和屏幕宽度来计算文本高度并将其传递给

AppBar
toolbarHeight

class AppBarHeightCalc {
  String title;
  double width;
  AppBarHeightCalc({
    required this.title,
    required this.width,
  });

double horizontalPadding = 32;
double actionsWidth = 48;
final style = TextStyle(fontSize: 26);

  double calculateHeight() {
    TextPainter textPainter = TextPainter()
      ..text = TextSpan(text: title, style: style)
      ..textDirection = TextDirection.ltr
      ..layout(minWidth: 0, maxWidth: width - horizontalPadding);
    return (textPainter.size.height);
  }

double calculateHeightWithActions() {
    TextPainter textPainter = TextPainter()
      ..text = TextSpan(text: title, style: style)
      ..textDirection = TextDirection.ltr
      ..layout(minWidth: 0, maxWidth: width - actionsWidth - horizontalPadding);
    return (textPainter.size.height);
  }
}

class AppBarExample extends StatelessWidget {
  const AppBarExample({super.key});

  @override
  Widget build(BuildContext context) {
    String title =
        'Lorem ipsum dolor sit amet. 33 nostrum neque qui possimus fugit ex fugiat';
    double screenWidth = MediaQuery.of(context).size.width;
    final appBarHeight = AppBarHeightCalc(title: title, width: screenWidth);
    return Scaffold(
        appBar: AppBar(
          title: Text(
            title,
            maxLines: 3,
          ),
          toolbarHeight: appBarHeight.calculateHeight(),
        ),
        body: Center());
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.