You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中解决自定义Dialog小屏幕无法滚动被截断的问题

问题

我制作了一个供用户修改内容的CustomDialog,发现在小屏幕设备上它无法滚动,导致内容被截断,甚至无法点击确认按钮。我看到其他相关问题中有人在调用showDialog时设置"scrolling: true",但该属性并不存在,不知道该如何配置。相关代码如下:

child: GestureDetector(
        onDoubleTap: () {
          showDialog(
              context: context,
              builder: (context) {
                return MaterialApp(
                  debugShowCheckedModeBanner: false,
                  title: 'iOrganize',
                  theme: ThemeData.dark().copyWith(
                    scaffoldBackgroundColor: secondBgColor,
                    textTheme: GoogleFonts.poppinsTextTheme(
                            Theme.of(context).textTheme)
                        .apply(bodyColor: primaryColor),
                  ),
                  home: CustomDialogModificarTarea(usuario, tarjeta),
                );
              });
        },

CustomDialogModificarTarea的完整代码:

class CustomDialogModificarTarea extends StatelessWidget {
  final Usuario usuario;
  final Tarjeta tarjeta;
  ProyectoService proyectoService = ProyectoServiceFirebase();
  UsuarioService usuarioService = UsuarioServiceFirebase();
  TarjetaService tarjetaService=TarjetaServiceFirebase();
  TextEditingController nombreController = TextEditingController();
  TextEditingController fechaController = TextEditingController();

  CustomDialogModificarTarea(this.usuario,this.tarjeta);

  @override
  Widget build(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(Consts.padding),
      ),
      elevation: 0.0,
      backgroundColor: Colors.transparent,
      child: dialogContent(context),
    );
  }

  dialogContent(BuildContext context) {
    return Stack(
      children: <Widget>[
        buildCard(context),
        buildCircle(),
        //...bottom card part,
        //...top circlular image part,
      ],
    );
  }

  Widget buildCard(BuildContext context) {
    return Positioned(
      top: 50,
      left: Consts.padding,
      right: Consts.padding * 2,
      child: Container(
        decoration: new BoxDecoration(
          color: secondBgColor,
          shape: BoxShape.rectangle,
          borderRadius: BorderRadius.circular(Consts.padding),
          boxShadow: [
            BoxShadow(
              color: Color.fromARGB(66, 0, 0, 0),
              blurRadius: 10.0,
              offset: const Offset(0.0, 10.0),
            ),
          ],
        ),
        padding: const EdgeInsets.only(
          top: Consts.avatarRadius + Consts.padding,
          bottom: Consts.avatarRadius + Consts.padding,
          left: Consts.avatarRadius + Consts.padding,
          right: Consts.avatarRadius + Consts.padding,
        ),
        margin: const EdgeInsets.only(top: Consts.avatarRadius),
        child: Column(
          mainAxisSize: MainAxisSize.min, // To make the card compact
          children: <Widget>[
            const Text(
              "Modificar tarea",
              style: TextStyle(
                fontSize: 24.0,
                fontWeight: FontWeight.w700,
              ),
            ),
            const SizedBox(height: 16.0),
            TextFormField(
              controller: nombreController,
              decoration: const InputDecoration(
                hintText: 'Cambiar el nombre de la tarea',
              ),
            ),
            TextFormField(
              controller: fechaController,
              decoration: const InputDecoration(
                hintText: 'Cambiar la fecha de la tarea',
              ),
            ),
            const SizedBox(height: 16.0),
            Align(
              alignment: Alignment.bottomLeft,
              child: TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text('Cancelar'),
              ),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: TextButton(
                onPressed: () {
                  
                  TablaService tablaService=TablaServiceFirebase();
                  int pos;
                  pos=int.tryParse(usuario.idProyectoActual)!;
                  TarjetaService tarjetaService=TarjetaServiceFirebase();
                  print("Borrar Tarjetas");
                  for(int i=0;i<2;i++){
                    List<Tarjeta>? tarjetas=usuario.proyectos![pos].tablas![i].tarjetas;
                    print(tarjetas!.length);
                    bool borrado=false;
                    for(int j=0; tarjetas!=null && j<tarjetas.length && !borrado;j++){
                      print("Segundo for");
                      if(tarjetas[j].id==tarjeta.id){
                        print("La he encontrado $i ${tarjetas[j].id}");
                        tarjetas.removeAt(j);
                         usuario.proyectos![pos].tablas![i].tarjetas=tarjetas;
                         print(usuario.proyectos![pos].tablas![i].tarjetas!.length);
                        borrado=true;
                      }
                    }
                    print("Imprimo el id: ${usuario.proyectos![pos].tablas![i].id!.split("-")[1] }");
                     tablaService.updateTabla(id: usuario.proyectos![pos].tablas![i].id!.split("-")[1], tipo: usuario.proyectos![pos].tablas![i].id!.split("-")[0], t: usuario.proyectos![pos].tablas![i]);
                  }
                  print("Salgo ta");
                  tarjetaService.deleteTarjeta(id: tarjeta.id);
                 

                  Navigator.of(context).pop();
                },
                child: const Text('Borrar tarea'),
              ),
            ),
            Align(
              alignment: Alignment.bottomRight,
              child: TextButton(
                onPressed: () async {
                  
                  if(nombreController.text!=""){
                    tarjeta.name=nombreController.text;
                  }
                  if(fechaController.text!=""){
                    tarjeta.fecha=fechaController.text;
                  }
                  
                  tarjetaService.updateTarjeta(tarjeta: tarjeta);
                  Navigator.of(context).pop();
                },
                child: const Text('Modificar'),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget buildCircle() {
    return const Positioned(
      right: 16,
      top: 50,
      child: const CircleAvatar(
        backgroundColor: Colors.blueAccent,
        radius: Consts.avatarRadius,
      ),
    );
  }
}

class Consts {
  Consts._();

  static const double padding = 16.0;
  static const double avatarRadius = 16.0;
}
解决方案

1. 移除showDialog中的MaterialApp嵌套

showDialog无需嵌套全新的MaterialApp,直接返回CustomDialogModificarTarea即可,避免上下文混乱:

child: GestureDetector(
  onDoubleTap: () {
    showDialog(
      context: context,
      builder: (context) {
        return CustomDialogModificarTarea(usuario, tarjeta);
      }
    );
  },
),

2. 给Dialog内容添加滚动容器

核心问题是内容无滚动支持,将包裹内容的Column用SingleChildScrollView包裹,确保小屏幕下可滚动:
修改buildCard方法中的Container子组件:

child: SingleChildScrollView(
  child: Column(
    mainAxisSize: MainAxisSize.min,
    children: <Widget>[
      // 原有内容保持不变
    ],
  ),
),

3. 优化布局减少垂直空间占用

将底部三个按钮改为Row布局,压缩垂直高度,同时调整Positioned布局避免内容挤压:
修改dialogContent方法:

dialogContent(BuildContext context) {
  return Stack(
    clipBehavior: Clip.none, // 允许头像超出容器范围
    children: <Widget>[
      Padding(
        padding: EdgeInsets.only(top: Consts.avatarRadius),
        child: buildCard(context),
      ),
      buildCircle(),
    ],
  );
}

修改buildCard方法,移除Positioned并调整按钮布局:

Widget buildCard(BuildContext context) {
  return Container(
    margin: EdgeInsets.symmetric(horizontal: Consts.padding),
    decoration: new BoxDecoration(
      color: secondBgColor,
      shape: BoxShape.rectangle,
      borderRadius: BorderRadius.circular(Consts.padding),
      boxShadow: [
        BoxShadow(
          color: Color.fromARGB(66, 0, 0, 0),
          blurRadius: 10.0,
          offset: const Offset(0.0, 10.0),
        ),
      ],
    ),
    padding: const EdgeInsets.only(
      top: Consts.avatarRadius + Consts.padding,
      bottom: Consts.padding,
      left: Consts.padding,
      right: Consts.padding,
    ),
    child: SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          const Text(
            "Modificar tarea",
            style: TextStyle(
              fontSize: 24.0,
              fontWeight: FontWeight.w700,
            ),
          ),
          const SizedBox(height: 16.0),
          TextFormField(
            controller: nombreController,
            decoration: const InputDecoration(
              hintText: 'Cambiar el nombre de la tarea',
            ),
          ),
          TextFormField(
            controller: fechaController,
            decoration: const InputDecoration(
              hintText: 'Cambiar la fecha de la tarea',
            ),
          ),
          const SizedBox(height: 16.0),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text('Cancelar'),
              ),
              TextButton(
                onPressed: () {
                  // 原有删除逻辑保持不变
                  Navigator.of(context).pop();
                },
                child: const Text('Borrar tarea'),
              ),
              TextButton(
                onPressed: () async {
                  // 原有修改逻辑保持不变
                  Navigator.of(context).pop();
                },
                child: const Text('Modificar'),
              ),
            ],
          ),
        ],
      ),
    ),
  );
}

最终完整代码

class CustomDialogModificarTarea extends StatelessWidget {
  final Usuario usuario;
  final Tarjeta tarjeta;
  ProyectoService proyectoService = ProyectoServiceFirebase();
  UsuarioService usuarioService = UsuarioServiceFirebase();
  TarjetaService tarjetaService=TarjetaServiceFirebase();
  TextEditingController nombreController = TextEditingController();
  TextEditingController fechaController = TextEditingController();

  CustomDialogModificarTarea(this.usuario,this.tarjeta);

  @override
  Widget build(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(Consts.padding),
      ),
      elevation: 0.0,
      backgroundColor: Colors.transparent,
      child: dialogContent(context),
    );
  }

  dialogContent(BuildContext context) {
    return Stack(
      clipBehavior: Clip.none,
      children: <Widget>[
        Padding(
          padding: EdgeInsets.only(top: Consts.avatarRadius),
          child: buildCard(context),
        ),
        buildCircle(),
      ],
    );
  }

  Widget buildCard(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: Consts.padding),
      decoration: new BoxDecoration(
        color: secondBgColor,
        shape: BoxShape.rectangle,
        borderRadius: BorderRadius.circular(Consts.padding),
        boxShadow: [
          BoxShadow(
            color: Color.fromARGB(66, 0, 0, 0),
            blurRadius: 10.0,
            offset: const Offset(0.0, 10.0),
          ),
        ],
      ),
      padding: const EdgeInsets.only(
        top: Consts.avatarRadius + Consts.padding,
        bottom: Consts.padding,
        left: Consts.padding,
        right: Consts.padding,
      ),
      child: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            const Text(
              "Modificar tarea",
              style: TextStyle(
                fontSize: 24.0,
                fontWeight: FontWeight.w700,
              ),
            ),
            const SizedBox(height: 16.0),
            TextFormField(
              controller: nombreController,
              decoration: const InputDecoration(
                hintText: 'Cambiar el nombre de la tarea',
              ),
            ),
            TextFormField(
              controller: fechaController,
              decoration: const InputDecoration(
                hintText: 'Cambiar la fecha de la tarea',
              ),
            ),
            const SizedBox(height: 16.0),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: const Text('Cancelar'),
                ),
                TextButton(
                  onPressed: () {
                    TablaService tablaService=TablaServiceFirebase();
                    int pos;
                    pos=int.tryParse(usuario.idProyectoActual)!;
                    TarjetaService tarjetaService=TarjetaServiceFirebase();
                    print("Borrar Tarjetas");
                    for(int i=0;i<2;i++){
                      List<Tarjeta>? tarjetas=usuario.proyectos![pos].tablas![i].tarjetas;
                      print(tarjetas!.length);
                      bool borrado=false;
                      for(int j=0; tarjetas!=null && j<tarjetas.length && !borrado;j++){
                        print("Segundo for");
                        if(tarjetas[j].id==tarjeta.id){
                          print("La he encontrado $i ${tarjetas[j].id}");
                          tarjetas.removeAt(j);
                          usuario.proyectos![pos].tablas![i].tarjetas=tarjetas;
                          print(usuario.proyectos![pos].tablas![i].tarjetas!.length);
                          borrado=true;
                        }
                      }
                      print("Imprimo el id: ${usuario.proyectos![pos].tablas![i].id!.split("-")[1] }");
                      tablaService.updateTabla(id: usuario.proyectos![pos].tablas![i].id!.split("-")[1], tipo: usuario.proyectos![pos].tablas![i].id!.split("-")[0], t: usuario.proyectos![pos].tablas![i]);
                    }
                    print("Salgo ta");
                    tarjetaService.deleteTarjeta(id: tarjeta.id);
                    Navigator.of(context).pop();
                  },
                  child: const Text('Borrar tarea'),
                ),
                TextButton(
                  onPressed: () async {
                    if(nombreController.text!=""){
                      tarjeta.name=nombreController.text;
                    }
                    if(fechaController.text!=""){
                      tarjeta.fecha=fechaController.text;
                    }
                    tarjetaService.updateTarjeta(tarjeta: tarjeta);
                    Navigator.of(context).pop();
                  },
                  child: const Text('Modificar'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget buildCircle() {
    return const Positioned(
      right: Consts.padding,
      top: -Consts.avatarRadius,
      child: CircleAvatar(
        backgroundColor: Colors.blueAccent,
        radius: Consts.avatarRadius,
      ),
    );
  }
}

class Consts {
  Consts._();

  static const double padding = 16.0;
  static const double avatarRadius = 16.0;
}

内容的提问来源于stack exchange,提问作者Tatiana Sánchez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:30:47