skip to Main Content

I have a new inventory screen that lets you create a new inventory, the problem is, when clicking Descripcion a Keyboard appears so you can write, and I already can hide it when clicking outside of it.

To improve the user experience, I want to conceal it when you click on a dropdown menu while the keyboard is up, and I’m unable to figure out how to do it.

This id the code:

class CreateInventory extends StatefulWidget {
  const CreateInventory({Key? key}) : super(key: key);

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

class _CreateInventoryState extends State<CreateInventory> {
  List<String> tiendas = globals.Globals.tiendasList;
  List<String> almacenes = [];
  List<String> tiposInventario = globals.Globals.tiposInventarioList;
  final TextEditingController _dateController = TextEditingController();

  DateTime _selectedDate = DateTime.now();
  final dateFormatter = DateFormat('dd/MM/yyyy hh:mm');
  String? descripcion = '';
  String? selectedTienda='';
  String? selectedAlmacen='';
  String? selectedTipoInventario='';

  @override
  void initState() {
    super.initState();
    _dateController.text = dateFormatter.format(_selectedDate);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        // Cierra el teclado cuando se toca fuera del TextField
        FocusScope.of(context).unfocus();
      },
      child: Scaffold(
        bottomNavigationBar: BuildBottomAppbar(
          descripcion: descripcion,
          selectedAlmacen: selectedAlmacen,
          selectedDate: _selectedDate,
          selectedTienda: selectedTienda,
          selectedTipoInventario: selectedTipoInventario,
        ),
        appBar: buildAppBar(),
        body: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(20.0),
            child: Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(20.0),
                color: Colors.grey.shade300,
              ),
              padding: const EdgeInsets.all(16.0),
              child: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(bottom: 16.0),
                      child: buildContainerDescripcion(),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(bottom: 16.0),
                      child: buildContainerTienda(),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(bottom: 16.0),
                      child: buildContainerAlmacen(),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(bottom: 16.0),
                      child: buildContainerTipoInv(),
                    ),
                    buildContainerFecha(context),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }


  Container buildContainerFecha(BuildContext context) {
    return Container(
      child: buildListTileFechaHora(context),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8.0),
        color: Colors.grey.shade200,
      ),
    );
  }

  Container buildContainerTipoInv() {
    return Container(
      child: buildListTileTipoInventario(),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8.0),
        color: Colors.grey.shade200,
      ),
    );
  }

  Container buildContainerTienda() {
    return Container(
      child: buildListTileTienda(),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8.0),
        color: Colors.grey.shade200,
      ),
    );
  }

  Container buildContainerDescripcion() {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8.0),
        color: Colors.grey.shade200,
      ),
      padding: const EdgeInsets.all(  16.0) ,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Descripción',
            style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 17,
            ),
          ),
          buildTextField(),
        ],
      ),
    );
  }

  Padding buildTextField() {
    return Padding(
      padding: const EdgeInsets.all(0.0),
      child: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(8.0),
          color: Colors.white,
        ),
        child: TextField(
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Descripción del inventario',
          ),
          onChanged: (text) {
            setState(() {
              descripcion = text;
            });
          },
        ),
      ),
    );
  }

  Container buildContainerAlmacen() {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16.0),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8.0),
        color: Colors.grey.shade200,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Almacen',
            style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 17,
            ),
          ),
          SizedBox(height: 8.0),
          selectedTienda != null&&selectedTienda!=''
              ? buildDropdownMenuAlmacenes()
              : Container(
            decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(
                color: Colors.red,
                width: 1.0,
              ),
              borderRadius: BorderRadius.circular(8.0),
            ),
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                'Seleccione una tienda',
                style: TextStyle(
                  color: Colors.red,
                  fontSize: 16.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  ListTile buildListTileFechaHora(BuildContext context) {
    return ListTile(
      title: const Text(
        'Fecha y Hora',
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 17,
        ),
      ),
      subtitle: Row(
        children: [
          Expanded(
            child: Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8.0),
                color: Colors.white,
              ),
              child: TextButton(
                onPressed: () async {
                  final DateTime currentTime =
                  DateTime.now(); // Get the current time

                  final DateTime? pickedDate = await showDatePicker(
                    context: context,
                    initialDate: currentTime,
                    firstDate: DateTime(2000),
                    lastDate: currentTime, // Set lastDate to current time
                  );
                  if (pickedDate != null) {
                    final TimeOfDay? pickedTime = await showTimePicker(
                      context: context,
                      initialTime: TimeOfDay.fromDateTime(currentTime),
                    );

                    if (pickedTime != null) {
                      final DateTime selectedDateTime = DateTime(
                        pickedDate.year,
                        pickedDate.month,
                        pickedDate.day,
                        pickedTime.hour,
                        pickedTime.minute,
                      );

                      if (selectedDateTime.isBefore(currentTime) ||
                          selectedDateTime.isAtSameMomentAs(currentTime)) {
                        // Check if the selected date and time are in the past or equal to the current time
                        setState(() {
                          _selectedDate = selectedDateTime;
                          _dateController.text = DateFormat('dd/MM/yyyy hh:mm')
                              .format(_selectedDate);
                        });
                      } else {
                        // Show a message or handle the case where the selected date and time are in the future
                        showDialog(
                          context: context,
                          builder: (context) {
                            return CupertinoAlertDialog(
                              title: Text('Invalid Date/Time'),
                              content: Text(
                                  'Please select a date and time that is equal to or earlier than the current time.'),
                              actions: [
                                TextButton(
                                  onPressed: () {
                                    Navigator.of(context).pop();
                                  },
                                  child: Text('OK'),
                                ),
                              ],
                            );
                          },
                        );
                      }
                    }
                  }
                },
                child: Text(
                  DateFormat('dd/MM/yyyy hh:mm').format(_selectedDate),
                  style: TextStyle(fontSize: 16),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }


  ListTile buildListTileTipoInventario() {
    return ListTile(
      title: const Text(
        'Tipo de inventario',
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 17,
        ),
      ),
      subtitle: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(8.0),
          color: Colors.white,
        ),
        child: LayoutBuilder(
          builder: (context, constraints) {
            return DropdownMenu<String>(
              width: constraints.maxWidth, // Set DropdownMenu width to the width of the subtitle container
              hintText: 'Selecciona un tipo de inventario',
              onSelected: (String? value) {
                setState(() {
                  selectedTipoInventario = value;
                });
              },
              dropdownMenuEntries: tiposInventario
                  .map<DropdownMenuEntry<String>>((String value) {
                return DropdownMenuEntry<String>(
                  value: value,
                  label: value,
                );
              }).toList(),
            );
          },
        ),
      ),
    );
  }


  ListTile buildListTileTienda() {
    return ListTile(
      title: const Text(
        'Tienda',
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 17,
        ),
      ),
      subtitle: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(8.0),
          color: Colors.white,
        ),
        child: LayoutBuilder(
          builder: (context, constraints) {
            return buildDropdownMenuTienda(constraints.maxWidth);
          },
        ),
      ),
    );
  }

  Container buildDropdownMenuAlmacenes() {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8.0),
        color: Colors.white,
      ),
      child: LayoutBuilder(
        builder: (context, constraints) {
          return DropdownMenu<String>(
            width: constraints.maxWidth,
            hintText: 'Selecciona un almacén',
            onSelected: (String? value) {
              final parts = value?.split('--');
              if (parts!.isNotEmpty) {
                final selectedPart = parts[0];
                setState(() {
                  updateAlmacenesSelect(selectedTienda!);
                  selectedAlmacen = selectedPart;
                });
              }
            },
            dropdownMenuEntries: almacenes
                .map<DropdownMenuEntry<String>>((String value) {
              return DropdownMenuEntry<String>(
                value: value,
                label: value,
              );
            }).toList(),
          );
        },
      ),
    );
  }


  DropdownMenu<String> buildDropdownMenuTienda(double maxWidth) {
    return DropdownMenu<String>(
      width: maxWidth,
      hintText: 'Selecciona una tienda',
      onSelected: (String? value) {
        setState(() {
          selectedTienda = value!;
          updateAlmacenesSelect(selectedTienda!);
        });
      },
      dropdownMenuEntries: tiendas
          .map<DropdownMenuEntry<String>>((String value) {
        return DropdownMenuEntry<String>(value: value, label: value);
      }).toList(),
    );
  }

  AppBar buildAppBar() {
    return AppBar(
      elevation: 0,
      automaticallyImplyLeading: false,
      title: const Center(
        child: Column(
          children: [
            Text(
              'Nuevo Inventario',
              style: TextStyle(
                color: AppColors.grisTexto,
                fontFamily: 'Lato',
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
      iconTheme: const IconThemeData(color: AppColors.grisTexto),
      backgroundColor: Colors.white,
    );
  }

  Future<void> updateAlmacenesSelect(String s) async {
    if (s.isNotEmpty&&s!='') {
      List<String> value =
      await globals.Globals.filterAlmacenesByTiendaId(s);
      setState(() {
        almacenes = value;
      });
    }
  }
}
class BuildBottomAppbar extends StatelessWidget {
  final DateTime selectedDate;
  final String? descripcion;
  final String? selectedTienda;
  final String? selectedAlmacen;
  final String? selectedTipoInventario;

  BuildBottomAppbar({
    required this.selectedDate,
    required this.descripcion,
    required this.selectedTienda,
    required this.selectedAlmacen,
    required this.selectedTipoInventario,
    Key? key,
  });

  @override
  Widget build(BuildContext context) {
    return BottomAppBar(
      color: Colors.white.withOpacity(0),
      height: 75,
      elevation: 0,
      child: Padding(
        padding: const EdgeInsets.all(10.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            FloatingActionButton(
              heroTag: 'btn1',
              onPressed: () {
                _dialogBuilder(context);
              },
              backgroundColor: Colors.red,
              child: const Icon(Icons.cancel),
            ),
            FloatingActionButton(
              heroTag: 'btn2',
              onPressed: () async {
                print('started');
                await uploadInventory();
                print('finished');

              },
              backgroundColor: Colors.green,
              child: const Icon(Icons.check),
            )
          ],
        ),
      ),
    );
  }

  Future<void> uploadInventory() async {
    print('uploading inventory');

    postInventario(
      selectedDate,
      descripcion!,
      // Replace with the appropriate value for idDominio
      selectedTienda!,
      // Replace with the appropriate value for idTienda
      selectedAlmacen!,
      // Replace with the appropriate value for idAlmacen
      selectedTipoInventario!, // Replace with the appropriate value for idTipoInventario
    );
    print('uploaded inventory');

  }

}


Future<void> _dialogBuilder(BuildContext context) {
  return showCupertinoDialog<void>(
    context: context,
    builder: (BuildContext context) {
      return CupertinoAlertDialog(
        title: Text(
          '¿Estás seguro que deseas cancelar la creación de un nuevo inventario?',
          style: TextStyle(
            fontSize: 18.0,
            fontWeight: FontWeight.bold,
          ),
        ),
        content: Text(
          'Si cancelas, se perderán todos los datos ingresados hasta el momento.',
          style: TextStyle(fontSize: 16.0),
        ),
        actions: <Widget>[
          CupertinoDialogAction(
            isDefaultAction: true,
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: Text('Cancelar'),
          ),
          CupertinoDialogAction(
            isDestructiveAction: true,
            onPressed: () {
              Navigator.of(context).pop();
              Navigator.of(context).pop();
            },
            child: Text('Aceptar'),
          ),
        ],
      );
    },
  );
}


Future<void> postInventario(DateTime fecha, String descripcion, String idTienda,
    String idAlmacen, String idTipoInventario) async {


  InventoryCreatorController inventoryCreatorController =
  InventoryCreatorController();
  String fechaFormateada = await getIds().getFormattedDate(fecha);
  int idTiendaFinal = await getIds.getIdTienda(idTienda);
  int idDominioFinal = await getIds().getIdDomain();
  int idAlmacenFinal = getIdAlmacen(idAlmacen)!;
  int idTipoInventarioFinal =
  await getIds.getIdTipoInventario(idTipoInventario);
  LoginController loginController = LoginController();
  await loginController.updateToken();
  await inventoryCreatorController.postInventario(fechaFormateada, descripcion,
      idDominioFinal, idTiendaFinal, idAlmacenFinal, idTipoInventarioFinal);
}

int? getIdAlmacen(String input) {
  String lastPart = input.split(' ').last;

  // Parse the last part to an integer
  return int.tryParse(lastPart);

}


class getIds {
  MainDbManager mainDbManager = MainDbManager();

  static  Future<int> getIdTipoInventario(String idTipoInventario) async {
    return await MainDbManager.fetchTipoInventarioId(idTipoInventario);
  }

  Future<int> getIdAlmacen(String idAlmacen) async {
    return await MainDbManager.fetchAlmacenId(idAlmacen);
  }

  Future<int> getIdDomain() async {
    return await MainDbManager.fetchDomainId();
  }

  static Future<int> getIdTienda(String idTienda) async {
    return await MainDbManager.fetchTiendaId(idTienda);
  }
  static Future<int>getIdEstadoInventario(String estadoInventario) async {
    return await MainDbManager.fetchEstadoInventarioId(estadoInventario);
  }

  getFormattedDate(DateTime fecha) {
    String formattedDate = DateFormat('dd/MM/yyyy hh:mm').format(fecha);

    return formattedDate;
  }
}

2

Answers


  1. Simply wrap your Myapp build function retrun with this GestureDetector

    behavior: HitTestBehavior.opaque,
              onTap: () {
                FocusScopeNode currentFocus = FocusScope.of(context);
                if (!currentFocus.hasPrimaryFocus &&
                    currentFocus.focusedChild != null) {
                  FocusManager.instance.primaryFocus!.unfocus();
                }
              },
    

    Here is complete code

        class MyApp extends StatelessWidget {
      final GlobalKey<NavigatorState> navigatorKey;
    
      const MyApp({Key? key, required this.navigatorKey}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MediaQuery(
            data: MediaQuery.of(context).copyWith(
              textScaler: TextScaler.linear(
                  MediaQuery.of(context).textScaleFactor.clamp(0.5, 1.5)),
            ),
            child: GestureDetector(
              behavior: HitTestBehavior.opaque,
              onTap: () {
                FocusScopeNode currentFocus = FocusScope.of(context);
                if (!currentFocus.hasPrimaryFocus &&
                    currentFocus.focusedChild != null) {
                  FocusManager.instance.primaryFocus!.unfocus();
                }
              },
              child: InkWell(
                onTap: (){
                  ///do your work 
                },
                child: Container(
                  child: Text("Go For Next Page"),
                ),
              ),
            ));
      }
    }
    

    it will dismiss keyboard when you tap on screen,
    applicable for complete project

    Login or Signup to reply.
  2.  FocusScopeNode currentFocus = FocusScope.of(context);
            if (!currentFocus.hasPrimaryFocus &&
                currentFocus.focusedChild != null) {
              FocusManager.instance.primaryFocus!.unfocus();
            }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search