In this example, we don't intend to use any packages
Image cover credit: Florian Farhay
Almost all mobile applications need to get different kinds of information from the user, such as their phone number, name, and so on.
To get this information, we use the virtual keyboard provided by the operating system.
In the Flutter framework, the widget responsible for this is called TextField.
However, one of the common errors in Flutter programming is the Overflow error. This error indicates that there isn't enough space to display the widgets.
This error can happen in various situations, and one of them is when the keyboard is shown.
To solve this problem, we can put the page content inside a scrollable widget like ListView or SingleChildScrollView.
But in some scenarios, we need to know when the keyboard opens so we can make changes to the layout of elements.
Generally, and as a basic way to understand how much space the keyboard takes up, we can use the code below.
SizedBox(height: MediaQuery.viewInsetsOf(context).bottom,)
However, this code cannot listen for changes in the keyboard's visibility.
So, in the following steps, we want to add this capability to our Flutter application.
Keyboard listener
The code below is a more advanced version of the previous code, written as a widget.
This widget figures out whether the keyboard is open or not by checking the size of viewInsets.
This widget also includes a child and a listener method. The listener's job is to listen for changes in the keyboard's state.
class KeyboardVisibilityListener extends StatefulWidget {
final Widget child;
final void Function(
bool isKeyboardVisible,
) listener;
const KeyboardVisibilityListener({
Key? key,
required this.child,
required this.listener,
}) : super(key: key);
@override
_KeyboardVisibilityListenerState createState() =>
_KeyboardVisibilityListenerState();
}
class _KeyboardVisibilityListenerState extends State<KeyboardVisibilityListener>
with WidgetsBindingObserver {
var _isKeyboardVisible = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeMetrics() {
final bottomInset = WidgetsBinding.instance.window.viewInsets.bottom;
final newValue = bottomInset > 0.0;
if (newValue != _isKeyboardVisible) {
_isKeyboardVisible = newValue;
widget.listener(_isKeyboardVisible);
}
}
@override
Widget build(BuildContext context) => widget.child;
}
To be able to change the child widget, or any other widget that we are not directly using here, at the same time as the keyboard state changes, we use the Provider package for state management.
We create a class to store the keyboard state and its changes, like the one below.
class KeyboardProvider extends ChangeNotifier{
late bool _isKeyboardOpen;
KeyboardProvider(){
_isKeyboardOpen = false;
}
ChangeKeyboardState({required bool KeyboardState}){
_isKeyboardOpen = KeyboardState;
notifyListeners();
}
bool KeyboardState() => _isKeyboardOpen;
}
Now, to use the code, you can do the following: In the listener method, we update the value of the variable stored in KeyboardProvider.
This way, the widgets that depend on it will be notified of the changes.
KeyboardVisibilityListener(
listener: (isKeyboardVisible) {
context.read<KeyboardProvider>().ChangeKeyboardState(KeyboardState: isKeyboardVisible);
},
child: Consumer<KeyboardProvider>(
builder: (context, value, child) {
if(value.KeyboardState()){
return Container();
}else{
return Text("Keyboard is closed");
}
My website: Hesam.cc
Top comments (0)