Skip to content

Commit 1b80cc0

Browse files
committed
Attempting to fix focus bug in flutter 3.7.0. Might be related to flutter/flutter#97389
1 parent 8b4ae95 commit 1b80cc0

File tree

5 files changed

+108
-130
lines changed

5 files changed

+108
-130
lines changed

.flutter-plugins-dependencies

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_keyboard_visibility","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-5.4.0/","native_build":true,"dependencies":[]}],"android":[{"name":"flutter_keyboard_visibility","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-5.4.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"flutter_keyboard_visibility_macos","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[]}],"linux":[{"name":"flutter_keyboard_visibility_linux","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[]}],"windows":[{"name":"flutter_keyboard_visibility_windows","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[]}],"web":[{"name":"flutter_keyboard_visibility_web","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_web-2.0.0/","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_keyboard_visibility","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_web","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_web","dependencies":[]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]}],"date_created":"2023-01-27 12:53:40.563305","version":"3.7.0"}
1+
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_keyboard_visibility","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-5.4.0/","native_build":true,"dependencies":[]}],"android":[{"name":"flutter_keyboard_visibility","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility-5.4.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"flutter_keyboard_visibility_macos","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[]}],"linux":[{"name":"flutter_keyboard_visibility_linux","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[]}],"windows":[{"name":"flutter_keyboard_visibility_windows","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[]}],"web":[{"name":"flutter_keyboard_visibility_web","path":"/home/dsyrstad/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_web-2.0.0/","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_keyboard_visibility","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_web","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_web","dependencies":[]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]}],"date_created":"2023-02-15 13:02:35.526917","version":"3.7.3"}

example/lib/main.dart

Lines changed: 91 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -49,91 +49,97 @@ class _MyHomePageState extends State<MyHomePage> {
4949
appBar: AppBar(
5050
title: const Text('VSC Datetime Field Demo'),
5151
),
52-
body: SingleChildScrollView(
53-
child: Center(
54-
child: Container(
55-
padding: const EdgeInsets.fromLTRB(30, 30, 30, 30),
56-
width: 500,
57-
child: Column(
58-
crossAxisAlignment: CrossAxisAlignment.start,
59-
children: [
60-
ElevatedButton(
61-
onPressed: () => _valueController.value = DateTime.now(),
62-
child: const Text('Set date/time on fields')),
63-
const SizedBox(height: 30),
64-
VscDatetimeField(
65-
type: VscDatetimeFieldType.date,
66-
valueController: _valueController,
67-
textFieldConfiguration: const TextFieldConfiguration(
68-
decoration: InputDecoration(
69-
label: Text('Date only'),
70-
)),
71-
onValueChanged: (value) =>
72-
debugPrint('Date only field value: $value'),
73-
minValue: DateTime.parse('2020-02-15'),
74-
maxValue: DateTime.parse('2025-12-15'),
75-
),
76-
const SizedBox(height: 30),
77-
VscDatetimeField(
78-
type: VscDatetimeFieldType.datetime,
79-
valueController: _valueController,
80-
textFieldConfiguration: const TextFieldConfiguration(
81-
decoration: InputDecoration(
82-
label: Text('Datetime'),
83-
)),
84-
onValueChanged: (value) =>
85-
debugPrint('Datetime field value: $value'),
86-
minValue: DateTime.parse('2020-02-15 08:00:00'),
87-
maxValue: DateTime.parse('2025-12-15 17:00:00'),
88-
),
89-
const SizedBox(height: 30),
90-
VscDatetimeField(
91-
type: VscDatetimeFieldType.time,
92-
valueController: _valueController,
93-
textFieldConfiguration: const TextFieldConfiguration(
94-
decoration: InputDecoration(
95-
label: Text('Time only'),
96-
)),
97-
onValueChanged: (value) =>
98-
debugPrint('Time field value: $value'),
99-
minValue: DateTime.parse('1970-01-01 08:00:00'),
100-
maxValue: DateTime.parse('2099-01-01 17:00:00'),
101-
),
102-
const SizedBox(height: 30),
103-
VscDatetimeField(
104-
type: VscDatetimeFieldType.date,
105-
valueController: _valueController,
106-
textFieldConfiguration: const TextFieldConfiguration(
107-
decoration: InputDecoration(
108-
label: Text('Date - Read-only'),
109-
)),
110-
readOnly: true,
111-
),
112-
const SizedBox(height: 30),
113-
VscDatetimeField(
114-
type: VscDatetimeFieldType.datetime,
115-
valueController: _interactiveValueController,
116-
textFieldConfiguration: const TextFieldConfiguration(
117-
decoration: InputDecoration(
118-
label: Text(
119-
'Independent Datetime with interacting valueController'),
120-
)),
121-
onValueChanged: (dt) =>
122-
_interactiveValueController.value = dt,
123-
),
124-
const SizedBox(height: 30),
125-
ElevatedButton(
126-
child: const Text('Show date picker dialog'),
127-
onPressed: () {
128-
showDatePicker(
129-
context: context,
130-
initialDate: DateTime.now(),
131-
firstDate: DateTime.parse('2000-01-01'),
132-
lastDate: DateTime.parse('2026-01-01'),
133-
);
134-
},
135-
),
136-
],
52+
body: Focus(
53+
onFocusChange: (f) => debugPrint('One of the fields has focus=$f'),
54+
child: SingleChildScrollView(
55+
child: Center(
56+
child: Container(
57+
padding: const EdgeInsets.fromLTRB(30, 30, 30, 30),
58+
width: 500,
59+
child: Column(
60+
crossAxisAlignment: CrossAxisAlignment.start,
61+
children: [
62+
ElevatedButton(
63+
onPressed: () => _valueController.value = DateTime.now(),
64+
child: const Text('Set date/time on fields')),
65+
const SizedBox(height: 30),
66+
VscDatetimeField(
67+
type: VscDatetimeFieldType.date,
68+
valueController: _valueController,
69+
textFieldConfiguration: const TextFieldConfiguration(
70+
decoration: InputDecoration(
71+
label: Text('Date only'),
72+
)),
73+
onValueChanged: (value) =>
74+
debugPrint('Date only field value: $value'),
75+
minValue: DateTime.parse('2020-02-15'),
76+
maxValue: DateTime.parse('2025-12-15'),
77+
),
78+
const SizedBox(height: 30),
79+
VscDatetimeField(
80+
type: VscDatetimeFieldType.datetime,
81+
valueController: _valueController,
82+
textFieldConfiguration: const TextFieldConfiguration(
83+
decoration: InputDecoration(
84+
label: Text('Datetime'),
85+
)),
86+
onValueChanged: (value) =>
87+
debugPrint('Datetime field value: $value'),
88+
minValue: DateTime.parse('2020-02-15 08:00:00'),
89+
maxValue: DateTime.parse('2025-12-15 17:00:00'),
90+
),
91+
const SizedBox(height: 30),
92+
VscDatetimeField(
93+
type: VscDatetimeFieldType.time,
94+
valueController: _valueController,
95+
textFieldConfiguration: const TextFieldConfiguration(
96+
decoration: InputDecoration(
97+
label: Text('Time only'),
98+
)),
99+
onValueChanged: (value) =>
100+
debugPrint('Time field value: $value'),
101+
minValue: DateTime.parse('1970-01-01 08:00:00'),
102+
maxValue: DateTime.parse('2099-01-01 17:00:00'),
103+
),
104+
const SizedBox(height: 30),
105+
VscDatetimeField(
106+
type: VscDatetimeFieldType.date,
107+
valueController: _valueController,
108+
textFieldConfiguration: const TextFieldConfiguration(
109+
decoration: InputDecoration(
110+
label: Text('Date - Read-only'),
111+
)),
112+
onValueChanged: (value) =>
113+
debugPrint('Read-only date field value: $value'),
114+
readOnly: true,
115+
),
116+
const SizedBox(height: 30),
117+
VscDatetimeField(
118+
type: VscDatetimeFieldType.datetime,
119+
valueController: _interactiveValueController,
120+
textFieldConfiguration: const TextFieldConfiguration(
121+
decoration: InputDecoration(
122+
label: Text(
123+
'Independent Datetime with interacting valueController'),
124+
)),
125+
onValueChanged: (dt) =>
126+
_interactiveValueController.value = dt,
127+
),
128+
const SizedBox(height: 30),
129+
ElevatedButton(
130+
child: const Text('Show date picker dialog'),
131+
onPressed: () async {
132+
final selectedDateTime = await showDatePicker(
133+
context: context,
134+
initialDate: DateTime.now(),
135+
firstDate: DateTime.parse('2000-01-01'),
136+
lastDate: DateTime.parse('2026-01-01'),
137+
);
138+
debugPrint('Selected $selectedDateTime from dialog');
139+
},
140+
),
141+
],
142+
),
137143
),
138144
),
139145
),

example/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,5 +261,5 @@ packages:
261261
source: path
262262
version: "0.0.1"
263263
sdks:
264-
dart: ">=2.18.0 <4.0.0"
264+
dart: ">=2.18.0 <3.0.0"
265265
flutter: ">=1.20.0"

lib/vsc_datetime_field.dart

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class VscDatetimeField extends StatefulWidget {
7676
final double pickerVerticalOffset;
7777

7878
/// If set to true, in the case where the Picker Box has less than
79-
/// _PickerBoxController.minOverlaySpace to grow in the desired [direction], the direction axis
79+
/// _PickerBox.minOverlaySpace to grow in the desired [direction], the direction axis
8080
/// will be temporarily flipped if there's more room available in the opposite
8181
/// direction.
8282
///
@@ -233,7 +233,8 @@ class VscDatetimeField extends StatefulWidget {
233233
}
234234

235235
class VscDatetimeFieldState extends State<VscDatetimeField> {
236-
late final FocusNode _focusNode = FocusNode();
236+
late final FocusNode _focusNode =
237+
FocusNode(debugLabel: 'VscDatetimeFieldState');
237238
late final TextEditingController _textEditingController =
238239
TextEditingController();
239240
late final _PickerBox _pickerBox;
@@ -306,7 +307,7 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
306307

307308
@override
308309
void dispose() {
309-
_pickerBox.close();
310+
_pickerBox.dispose();
310311
_pickerBox.widgetMounted = false;
311312
_keyboardVisibilitySubscription?.cancel();
312313
_effectiveFocusNode.removeListener(_focusNodeListener);
@@ -431,9 +432,6 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
431432
? InkResponse(
432433
radius: 24,
433434
canRequestFocus: false,
434-
child: Icon(widget.type == VscDatetimeFieldType.time
435-
? Icons.access_time_outlined
436-
: Icons.event_outlined),
437435
onTap: widget.readOnly ||
438436
widget.type == VscDatetimeFieldType.time
439437
? null
@@ -445,6 +443,9 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
445443
_effectiveFocusNode.requestFocus();
446444
}
447445
},
446+
child: Icon(widget.type == VscDatetimeFieldType.time
447+
? Icons.access_time_outlined
448+
: Icons.event_outlined),
448449
)
449450
: InkResponse(
450451
radius: 24,
@@ -831,6 +832,11 @@ class _PickerBox {
831832
_PickerBox(this.context, this.direction, this.autoFlipDirection)
832833
: desiredDirection = direction;
833834

835+
void dispose() {
836+
close();
837+
widgetMounted = false;
838+
}
839+
834840
void open() {
835841
final widget = context.widget as VscDatetimeField;
836842
if (widget.readOnly || isOpened || _overlayEntry == null) return;
@@ -882,7 +888,8 @@ class _PickerBox {
882888
await Future<void>.delayed(const Duration(milliseconds: 170));
883889
timer += 170;
884890

885-
if (widgetMounted &&
891+
final mounted = widgetMounted;
892+
if (mounted &&
886893
(MediaQuery.of(context).viewInsets != initial ||
887894
_findRootMediaQuery() != initialRootMediaQuery)) {
888895
return true;
@@ -1015,38 +1022,3 @@ class _PickerBox {
10151022
}
10161023
}
10171024
}
1018-
1019-
/// Supply an instance of this class to the [VscDatetimeField.pickerBoxController]
1020-
/// property to manually control the Picker Box
1021-
class PickerBoxController {
1022-
_PickerBox? _pickerBox;
1023-
FocusNode? _effectiveFocusNode;
1024-
1025-
/// Opens the Picker Box
1026-
void open() {
1027-
_effectiveFocusNode!.requestFocus();
1028-
}
1029-
1030-
bool isOpened() {
1031-
return _pickerBox!.isOpened;
1032-
}
1033-
1034-
/// Closes the Picker Box
1035-
void close() {
1036-
_effectiveFocusNode!.unfocus();
1037-
}
1038-
1039-
/// Opens the Picker Box if closed and vice-versa
1040-
void toggle() {
1041-
if (_pickerBox!.isOpened) {
1042-
close();
1043-
} else {
1044-
open();
1045-
}
1046-
}
1047-
1048-
/// Recalculates the height of the Picker Box
1049-
void resize() {
1050-
_pickerBox!.resize();
1051-
}
1052-
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dev_dependencies:
1818
flutter_test:
1919
sdk: flutter
2020

21-
flutter_lints: ^1.0.4
21+
flutter_lints: ^2.0.1
2222
test_cov_console: ^0.2.2
2323

2424
flutter:

0 commit comments

Comments
 (0)