如何在单击另一个字段时隐藏键盘?

问题描述 投票:0回答:1
我有一个新的库存屏幕,可以让您创建新的库存,问题是,当单击描述时,会出现一个键盘,以便您可以书写,并且

我已经可以在单击外部时隐藏它

为了改善用户体验,我想在键盘打开时单击下拉菜单时隐藏它,但我不知道如何做到这一点。

这就是代码:

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; } }
    
android flutter android-studio user-interface android-softkeyboard
1个回答
0
投票
只需使用此 GestureDetector 包装您的 Myapp 构建函数重新运行

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

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"), ), ), )); } }
当您点击屏幕时,它会关闭键盘,
适用于完整项目

© www.soinside.com 2019 - 2024. All rights reserved.