Flutter:滚动时将简单对话框转换为全屏对话框 [英] Flutter: Convert Simple Dialog To Full Screen Dialog On Scroll

查看:79
本文介绍了Flutter:滚动时将简单对话框转换为全屏对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我脑海中有一个UI布局,与Google Maps应用程序中的新菜单/帐户选择器基本相同.这是一个模式对话框,在按下配置文件按钮时会弹出并可以滚动.滚动后,该对话框会动画显示为全屏对话框,反之亦然.

I have a UI layout in my head, essentially the same as the new menu/account chooser as in the Google Maps app. It is a modal dialog that pops up on the press of the profile button and is scrollable. When scrolled, the dialog animates into a full screen dialog, and vice-versa.

我的目标是使用与Material Design兼容的方式来执行此操作,并且目前它仅需要在Android上运行.

I am aiming to use a Material Design compatible way of doing this, and it currently only needs to work on Android.

会进行一些小的更改,但是我的问题是:在Flutter中可能吗?谢谢.

Some minor changes would be made, but my question is: Is that possible in Flutter? Thanks.

推荐答案

在这里作者,我已经创建了这个菜单,代码片段如下:

Author here, I have created this menu, and the code snippet is below:

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import - ANOTHER PACKAGE -
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:theme_provider/theme_provider.dart';

import '../../services/authManager.dart';
import '../../services/models.dart';
import '../home.dart';

class MainMenu extends StatefulWidget {
  const MainMenu({
    Key key,
  }) : super(key: key);

  @override
  _MainMenuState createState() => _MainMenuState();
}

class _MainMenuState extends State<MainMenu>
    with SingleTickerProviderStateMixin {
  @override
  Widget build(BuildContext context) {
    final mainProps = Provider.of<MainProps>(context);
    final authVals = Provider.of<AuthVals>(context);
    final userData = Provider.of<CustomUser>(context);
    final userDataPrivate = Provider.of<CustomUserPrivate>(context);
    final userDataReadOnly = Provider.of<CustomUserReadOnly>(context);

    return IgnorePointer(
      ignoring: !mainProps.menuOpen,
      child: AnimatedOpacity(
        opacity: mainProps.menuOpen ? 1 : 0,
        duration: Duration(milliseconds: 150),
        child: Container(
          color: Colors.black.withOpacity(0.75),
          child: Stack(
            children: [
              SafeArea(
                child: Container(
                  width: MediaQuery.of(context).size.width,
                  margin: EdgeInsets.only(
                    top: mainProps.menuPadTop + 10,
                    left: mainProps.menuPadLeft,
                    right: mainProps.menuPadRight,
                  ),
                  child: Container(
                    width: 100.0,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.all(
                          Radius.circular(mainProps.menuCorners)),
                      color: Theme.of(context).backgroundColor,
                    ),
                    padding: EdgeInsets.only(
                      top: 10,
                      left: 10,
                      right: 10,
                    ),
                    child: NotificationListener<ScrollNotification>(
                      onNotification: (scrollNotification) {
                        if (scrollNotification is ScrollEndNotification) {
                          if (((mainProps.menuScrollCtrl.position.pixels > 100
                                          ? 100
                                          : mainProps
                                              .menuScrollCtrl.position.pixels) -
           

                       100)
                              .abs() >=
                          25) {
                        WidgetsBinding.instance.addPostFrameCallback((_) {
                          mainProps.menuScrollCtrl.animateTo(0,
                              duration: Duration(milliseconds: 150),
                              curve: Curves.easeInOut);
                        });
                      } else if (mainProps.menuScrollCtrl.position.pixels
                                  .abs() >
                              75 &&
                          mainProps.menuScrollCtrl.position.pixels.abs() <
                              100) {
                        WidgetsBinding.instance.addPostFrameCallback((_) {
                          mainProps.menuScrollCtrl.animateTo(100,
                              duration: Duration(milliseconds: 150),
                              curve: Curves.easeInOut);
                        });
                      }
                    }
                    return true;
                  },
                  child: Container(
                    height: 155,
                    child: Padding(
                      padding: const EdgeInsets.only(top: 8.0),
                      child: Column(
                        children: [
                          Row(
                            crossAxisAlignment: CrossAxisAlignment.baseline,
                            mainAxisAlignment:
                                MainAxisAlignment.spaceEvenly,
                            children: [
                              (userData.public != 'Local Account'
                                  ? CircleAvatar(
                                      radius: 20,
                                      backgroundImage: NetworkImage(
                                        authVals.authUser.photoURL,
                                      ),
                                    )
                                  : CircleAvatar(
                                      radius: 20,
                                      child: SvgPicture.network(
                                          userData.photoURL,
                                          color: Theme.of(context)
                                                      .primaryColor ==
                                                  Color(0xffff9800)
                                              ? Colors.black
                                              : Colors.white),
                                      backgroundColor:
                                          Theme.of(context).backgroundColor,
                                    )),
                              Column(
                                children: [
                                  Text(
                                    userData.publicExt,
                                    style: TextStyle(
                                        fontWeight: FontWeight.bold),
                                  ),
                                  Text(userDataPrivate?.realName ??
                                      'Please Wait...'),
                                  Text(authVals.authUser.email == ''
                                      ? 'Anonymous'
                                      : authVals.authUser.email),
                                  Text(userDataReadOnly != null
                                      ? userDataReadOnly.joined
                                          .toDate()
                                          .toLocal()
                                          .toString()
                                      : 'Please Wait...'),
                                ],
                              ),
                            ],
                          ),
                          Spacer(),
                          Row(
                            mainAxisAlignment:
                                MainAxisAlignment.spaceEvenly,
                            children: [
                              Visibility(
                                visible: !mainProps.signingOut,
                                child: OutlineButton(
                                  onPressed: null,
                                  child: Row(
                                    mainAxisSize: MainAxisSize.min,
                                    children: [
                                      Icon(Icons.account_circle),
                                      SizedBox(width: 15),
                                      Text('View Profile'),
                                    ],
                                  ),
                                ),
                              ),
                              OutlineButton(
                                onPressed: () async {
                                  if (!mainProps.signingOut) {
                                    mainProps.signingOut = true;
                                  } else {
                                    await AuthService().signOut();
                                    Navigator.of(context).popAndPushNamed(
                                        -SCREEN-);
                                  }
                                },
                                child: AnimatedContainer(
                                  duration: Duration(milliseconds: 250),
                                  constraints: mainProps.signingOut
                                      ? BoxConstraints(
                                          maxWidth: MediaQuery.of(context)
                                                  .size
                                                  .width -
                                              82)
                                      : BoxConstraints(maxWidth: 93),
                                  child: Row(
                                    mainAxisSize: !mainProps.signingOut
                                        ? MainAxisSize.min
                                        : MainAxisSize.max,
                                    mainAxisAlignment:
                                        MainAxisAlignment.center,
                                    children: [
                                      Icon(Icons.logout,
                                          color: mainProps.signingOut
                                              ? Colors.red
                                              : null),
                                      SizedBox(width: 15),
                                      LimitedBox(
                                        child: Text(
                                          'Sign Out',
                                          style: TextStyle(
                                              color: mainProps.signingOut
                                                  ? Colors.red
                                                  : null),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ],
                          ),
                          Spacer(),
                        ],
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
          SafeArea(
            child: Container(
              width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.height,
              margin: EdgeInsets.only(
                top: mainProps.menuPadTop +
                    (mainProps.menuScrollCtrl.hasClients
                        ? (((mainProps.compassExpanded ? 195 : 195) / 100) *
                            (100 -
                                (mainProps.menuScrollCtrl.position.pixels >
                                        100
                                    ? 100
                                    : mainProps
                                        .menuScrollCtrl.position.pixels)))
                        : -mainProps.menuPadTop),
                left: mainProps.menuPadLeft,
                right: mainProps.menuPadRight,
              ),
              child: Container(
                width: 100.0,
                height: 100.0,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(mainProps.menuCorners),
                    topRight: Radius.circular(mainProps.menuCorners),
                  ),
                  color: Theme.of(context).backgroundColor,
                ),
                padding: EdgeInsets.only(
                  top: 10,
                  left: 10,
                  right: 10,
                ),
                child: NotificationListener<ScrollNotification>(
                  onNotification: (scrollNotification) {
                    if (scrollNotification is ScrollEndNotification) {
                      if (((mainProps.menuScrollCtrl.position.pixels > 100
                                      ? 100
                                      : mainProps
                                          .menuScrollCtrl.position.pixels) -
                                  100)
                              .abs() >=
                          25) {
                        WidgetsBinding.instance.addPostFrameCallback((_) {
                          mainProps.menuScrollCtrl.animateTo(0,
                              duration: Duration(milliseconds: 150),
                              curve: Curves.easeInOut);
                        });
                      } else if (mainProps.menuScrollCtrl.position.pixels
                                  .abs() >
                              75 &&
                          mainProps.menuScrollCtrl.position.pixels.abs() <
                              100) {
                        WidgetsBinding.instance.addPostFrameCallback((_) {
                          mainProps.menuScrollCtrl.animateTo(100,
                              duration: Duration(milliseconds: 150),
                              curve: Curves.easeInOut);
                        });
                      }
                    }
                  },
                  child: SingleChildScrollView(
                    child: const Text(
                        'hello\n\n\n\na\n\n\n\no\n\n\n\na\n\n\n\no\n\n\n\na\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\no\n\n\n\n'),
                    controller: mainProps.menuScrollCtrl,
                  ),
                ),
              ),
            ),
          ),
          SafeArea(
            child: Container(
              width: MediaQuery.of(context).size.width,
              height: mainProps.compassExpanded ? 60 : 52,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.all(
                  Radius.circular(mainProps.menuCorners * 4),
                ),
              ),
              margin: EdgeInsets.only(
                top: mainProps.topMenuPadTop,
                left: mainProps.menuPadLeft,
                right: mainProps.menuPadRight,
              ),
              child: Material(
                borderRadius: BorderRadius.all(
                  Radius.circular(mainProps.menuCorners * 4),
                ),
                elevation: 4,
                color: Theme.of(context).backgroundColor,
                child: Row(
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(left: 10.0),
                      child: IconButton(
                        icon: Icon(Icons.close),
                        onPressed: () {
                          mainProps.menuOpen = false;
                          mainProps.signingOut = false;
                          mainProps.menuScrollCtrl.jumpTo(0);
                        },
                      ),
                    ),
                    Expanded(
                      child: Text(
                        -TEXT-,
                        style: GoogleFonts.ubuntu(
                          textStyle: TextStyle(fontSize: 17),
                          fontWeight: FontWeight.w600,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(right: 10.0),
                      child: Stack(
                        children: [
                          Opacity(
                            opacity: mainProps.menuScrollCtrl.hasClients
                                ? ((mainProps.menuScrollCtrl.position
                                                .pixels >
                                            100
                                        ? 0
                                        : 100 -
                                            mainProps.menuScrollCtrl
                                                .position.pixels) /
                                    100)
                                : 1,
                            child: IgnorePointer(
                              ignoring: mainProps.menuScrollCtrl.hasClients
                                  ? (mainProps.menuScrollCtrl.position
                                                  .pixels >=
                                              100
                                          ? -1
                                          : 100 -
                                              mainProps.menuScrollCtrl
                                                  .position.pixels) <
                                      0
                                  : false,
                              child: IconButton(
                                icon: Icon(Icons.palette),
                                onPressed: () => showDialog(
                                  context: context,
                                  builder: (_) => ThemeConsumer(
                                    child: ThemeDialog(
                                      title: Row(
                                        children: [
                                          Icon(Icons.palette),
                                          SizedBox(width: 15),
                                          Text('Choose Theme'),
                                        ],
                                      ),
                                      hasDescription: false,
                                    ),
                                  ),
                                ),
                              ),
                            ),
                          ),
                          Opacity(
                            opacity: 1.0 -
                                (mainProps.menuScrollCtrl.hasClients
                                    ? ((mainProps.menuScrollCtrl.position
                                                    .pixels >
                                                100
                                            ? 0
                                            : 100 -
                                                mainProps.menuScrollCtrl
                                                    .position.pixels) /
                                        100)
                                    : 1),
                            child: IgnorePointer(
                              ignoring:
                                  !(mainProps.menuScrollCtrl.hasClients
                                      ? (mainProps.menuScrollCtrl.position
                                                      .pixels >=
                                                  100
                                              ? -1
                                              : 100 -
                                                  mainProps.menuScrollCtrl
                                                      .position.pixels) <
                                          0
                                      : false),
                              child: IconButton(
                                icon: Icon(Icons.keyboard_arrow_down),
                                onPressed: () =>
                                    mainProps.menuScrollCtrl.animateTo(
                                  0,
                                  duration: Duration(milliseconds: 250),
                                  curve: Curves.easeInOut,
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    ),
  ),
);
  }
}

mainProps只是我使用提供程序的状态管理解决方案.使用setState进行此操作将是一场噩梦,并且可能会大量占用代码.我认为其余代码是不言自明的.它具有精美的动画和一些很酷的功能.

mainProps is just my state management solution, using Provider. Doing this using setState would be a nightmare and would probably bulk the code considerably. I think the rest of the code is self-explanatory. It has nice animations and some cool features.

您可以在这里看到它的工作: https://photos.app.goo.gl/aH6otb6CkbYbwpsr7

You can see it working here: https://photos.app.goo.gl/aH6otb6CkbYbwpsr7

我正在考虑使用与上面的代码相似的代码创建一个包,并在pub.dev上共享它.如果您认为这对您有帮助,请在此答案的评论中告诉我.

I'm considering creating a package with similar code to the code above, and sharing it on pub.dev. If you think that would help you, please let me know in the comments of this answer.

这篇关于Flutter:滚动时将简单对话框转换为全屏对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆