【问题标题】:How to make asset exceeds the AppBar?如何让资产超过 AppBar?
【发布时间】:2021-02-27 15:34:59
【问题描述】:

我想在 Flutter 中制作这个屏幕:

可以这样做吗?我的意思是让蜥蜴图退出AppBar并突出到主屏幕上?

这是资产:

【问题讨论】:

    标签: android flutter flutter-layout


    【解决方案1】:

    是的,您必须制作自己的自定义应用 Bar

    只需做一件事,将所有内容放入堆栈

    Stack(
    children:[
    Position(
    top:0,
    left:0
    child:YourLizardWidget()
    
    ),
    Position(
    top:0,
    left:0
    right:0
    child:YourAppBar()
    
    ),
    ])
    

    可能会起作用

    【讨论】:

    • 感谢@Rajshekhar Yadav 的快速回答,我尝试了解如何做到这一点,并会告诉你。
    【解决方案2】:

    使用应用程序的Scaffolddrawer 的另一种解决方案。

    注意:如果您已经使用drawer,您也可以使用endDrawer

    此解决方案为左侧动画的幻灯片添加了一个不错的小触感。 (从右侧滑动到末端抽屉)

    关于解决方案的几点说明:

    • AppBar 中,我指定了leading: new Container() 来隐藏汉堡菜单并为蜥蜴留出一些空间。
    • MyLizardMessage 中,我使用ColumnverticalDirection: VerticalDirection.up,这样我的图像(使用OverflowBox 显示在圆角Container 的顶部)

    完整源代码

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(
        MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Flutter Demo',
          home: HomePage(),
        ),
      );
    }
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            leading: new Container(),
            title: Text('Mes larfeuils'),
          ),
          drawer: MyLizardMessage(),
          body: MyContent(),
        );
      }
    }
    
    class MyLizardMessage extends StatelessWidget {
      const MyLizardMessage({
        Key key,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Column(
          verticalDirection: VerticalDirection.up,
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 0.0),
              child: Container(
                padding: EdgeInsets.all(8.0),
                decoration: BoxDecoration(
                  color: Colors.white,
                  border: Border.all(
                    color: Colors.black87,
                  ),
                  borderRadius: BorderRadius.all(
                    Radius.circular(20),
                  ),
                ),
                child: Text(
                    'Cupim beef ribs t-bone, shank short loin chicken pork belly prosciutto ribeye hamburger doner pork chop leberkas. '),
              ),
            ),
            IntrinsicWidth(
              child: Container(
                height: 82.0,
                child: OverflowBox(
                  maxHeight: 85.0,
                  child: Image.asset(
                    'images/lizard.png',
                    height: 85.0,
                  ),
                ),
              ),
            ),
          ],
        );
      }
    }
    
    class MyContent extends StatelessWidget {
      const MyContent({
        Key key,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
              Text(
                'Bacon ipsum dolor amet corned beef pork pork loin, chislic tri-tip picanha beef leberkas short ribs sirloin salami buffalo drumstick. Shankle chislic sirloin pork t-bone short ribs swine sausage hamburger chicken tail. Ham hock doner pancetta, jowl hamburger bacon prosciutto. Strip steak picanha jerky chislic. Strip steak prosciutto beef, pastrami corned beef t-bone frankfurter bacon rump sausage swine filet mignon fatback pork loin. Swine shank short ribs ham porchetta.',
              ),
              const SizedBox(height: 16.0),
              ElevatedButton(
                  onPressed: () => Scaffold.of(context).openDrawer(),
                  child: Text('Open message dialog')),
              const SizedBox(height: 16.0),
              Text(
                'T-bone venison picanha, corned beef meatloaf bacon buffalo sirloin biltong pancetta strip steak. Ham hock meatloaf tongue pastrami t-bone. Flank prosciutto shoulder chicken, turducken biltong hamburger short ribs beef buffalo brisket chislic filet mignon. Short ribs pork chop jowl jerky, beef ribs sirloin beef kevin landjaeger boudin chislic shankle. Tail pastrami swine drumstick, landjaeger turkey pig ground round.',
              ),
            ],
          ),
        );
      }
    }
    

    【讨论】:

    • 这个解决方案很聪明,问题是,当抽屉打开时,你不能使用de body screen,如果使用点击任意位置的按钮,抽屉就会关闭。
    • 正确。这带来了另一个解决方案。等待两分钟。
    • 好的,如果你找到了一个带抽屉的解决方案,那应该非常适合需要动画的屏幕。
    • 我的另一个解决方案是不使用 App Drawer。
    【解决方案3】:

    这是另一个使用 OverlayEntry 的解决方案。

    这一次,您可以定义消息出现时的动画。但是消息是非模态的。您仍然可以使用消息下方的应用程序 UI。在上面的截屏视频中,我通过单击ElevatedButton 打开消息,然后使用相同的按钮和消息中的关闭图标将其关闭。我还展示了AppBar 操作按钮在显示消息时也是可点击的。

    完整源代码

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(
        MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Flutter Demo',
          home: HomePage(),
        ),
      );
    }
    
    class HomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            leading: new Container(),
            title: Text('Mes larfeuils'),
            actions: [IconButton(icon: Icon(Icons.add), onPressed: () {})],
          ),
          body: MyContent(),
        );
      }
    }
    
    class MyLizardMessage extends StatefulWidget {
      final VoidCallback onClose;
    
      const MyLizardMessage({
        Key key,
        this.onClose,
      }) : super(key: key);
    
      @override
      _MyLizardMessageState createState() => _MyLizardMessageState();
    }
    
    class _MyLizardMessageState extends State<MyLizardMessage>
        with SingleTickerProviderStateMixin {
      AnimationController controller;
      Animation<Offset> position;
    
      @override
      void initState() {
        super.initState();
    
        controller =
            AnimationController(vsync: this, duration: Duration(milliseconds: 300));
        position = Tween<Offset>(begin: Offset(-1.0, 0.0), end: Offset.zero)
            .animate(CurvedAnimation(parent: controller, curve: Curves.easeInOut));
    
        controller.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        return SlideTransition(
          position: position,
          child: Column(
            verticalDirection: VerticalDirection.up,
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              Material(
                child: Padding(
                  padding:
                      const EdgeInsets.symmetric(horizontal: 8.0, vertical: 0.0),
                  child: Container(
                    padding: EdgeInsets.all(8.0),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      border: Border.all(
                        color: Colors.black87,
                      ),
                      borderRadius: BorderRadius.all(
                        Radius.circular(20),
                      ),
                    ),
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Expanded(
                          child: Text(
                            'Cupim beef ribs t-bone, shank short loin chicken pork belly prosciutto ribeye hamburger doner pork chop leberkas. ',
                            style: TextStyle(inherit: false),
                          ),
                        ),
                        GestureDetector(
                          onTap: () => widget.onClose?.call(),
                          child: Icon(Icons.close),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
              IntrinsicWidth(
                child: Container(
                  height: 82.0,
                  child: OverflowBox(
                    maxHeight: 85.0,
                    child: Image.asset(
                      'images/lizard.png',
                      height: 85.0,
                    ),
                  ),
                ),
              ),
            ],
          ),
        );
      }
    }
    
    class MyContent extends StatefulWidget {
      const MyContent({
        Key key,
      }) : super(key: key);
    
      @override
      _MyContentState createState() => _MyContentState();
    }
    
    class _MyContentState extends State<MyContent> {
      OverlayEntry _overlayEntry;
      bool get _isMessageShown => _overlayEntry != null && _overlayEntry.mounted;
    
      OverlayEntry _createOverlayEntry() {
        return OverlayEntry(
          builder: (context) {
            final width = MediaQuery.of(context).size.width;
            return Positioned(
              top: 0,
              left: 0,
              width: width,
              child: MyLizardMessage(onClose: () => _hideMessage()),
            );
          },
          opaque: false,
        );
      }
    
      _showMessage() {
        _overlayEntry = _createOverlayEntry();
        Overlay.of(context).insert(_overlayEntry);
        setState(() {});
      }
    
      _hideMessage() {
        _overlayEntry?.remove();
        _overlayEntry = null;
        setState(() {});
      }
    
      _toggleMessage() => _isMessageShown ? _hideMessage() : _showMessage();
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
              Text(
                'Bacon ipsum dolor amet corned beef pork pork loin, chislic tri-tip picanha beef leberkas short ribs sirloin salami buffalo drumstick. Shankle chislic sirloin pork t-bone short ribs swine sausage hamburger chicken tail. Ham hock doner pancetta, jowl hamburger bacon prosciutto. Strip steak picanha jerky chislic. Strip steak prosciutto beef, pastrami corned beef t-bone frankfurter bacon rump sausage swine filet mignon fatback pork loin. Swine shank short ribs ham porchetta.',
              ),
              const SizedBox(height: 16.0),
              ElevatedButton(
                  onPressed: () => _toggleMessage(),
                  child: Text(_isMessageShown
                      ? 'Close message dialog'
                      : 'Open message dialog')),
              const SizedBox(height: 16.0),
              Text(
                'T-bone venison picanha, corned beef meatloaf bacon buffalo sirloin biltong pancetta strip steak. Ham hock meatloaf tongue pastrami t-bone. Flank prosciutto shoulder chicken, turducken biltong hamburger short ribs beef buffalo brisket chislic filet mignon. Short ribs pork chop jowl jerky, beef ribs sirloin beef kevin landjaeger boudin chislic shankle. Tail pastrami swine drumstick, landjaeger turkey pig ground round.',
              ),
            ],
          ),
        );
      }
    }
    

    【讨论】:

      【解决方案4】:

      您可以执行以下操作:

      class NextPage extends StatefulWidget {
      
        @override
        _NextPageState createState() => _NextPageState();
      }
      
      class _NextPageState extends State<NextPage> {
      
        @override
        Widget build(BuildContext context) {
          return SafeArea(
            child: Scaffold(
              extendBodyBehindAppBar: true,
              backgroundColor: Colors.white,
              appBar: PreferredSize(
                preferredSize: Size(MediaQuery.of(context).size.width,200),
                child: Container(
                  child: Stack(
                    alignment: Alignment.topLeft,
                    children: <Widget>[
                      Container(color: Colors.red,width: MediaQuery.of(context).size.width,height: 100,),
                      Container(width: 100,height: 200,color: Colors.blue,),
                    ],
                  ),
                ),
              ),
              body: Container(color: Colors.amber,),
            ),
          );
        }
      }
      
      1. 我添加了一个 PreferredSize 小部件。它就像一个定义应用栏最大宽度和高度的容器。

      2. 我添加了extendBodyBehindAppBar: true 属性,以便正文部分将从屏幕顶部开始,而不是从应用栏下方开始。

      3. 然后我简单地将我的自定义应用栏添加为子属性。

      这是上面代码的结果。 (红色容器将是您的自定义应用栏,蓝色容器可以替换为您的资产)

      【讨论】:

        猜你喜欢
        • 2023-02-18
        • 2021-07-10
        • 2012-04-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-16
        • 2016-10-06
        • 2022-09-27
        • 2012-03-15
        相关资源
        最近更新 更多