Reputation: 701
Is there any way to detect when a widget changes position? Such as when the keyboard pops up and the content is shifted up? I would like to detect this without relying on focus events or trying to detect the keyboard state.
Here's an example app:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: MyTextField()
)
)
);
}
}
class MyTextField extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextField();
}
}
How can you detect when MyTextField
is moved up when it is focused?
Upvotes: 3
Views: 5338
Reputation: 1439
If you just want to find out if the keyboard is visible, you can use this:
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeMetrics() {
print('Is the keyboard visible? ${window.viewInsets.bottom != 0 ? 'yes' : 'no'}');
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: TextField(),
),
),
);
}
}
Explaination: By getting the bottom position of the rectangle in which your app is drawn, you can deduce whether a system component has reduced the space of your app, hence if the keyboard is visible.
This answers only this part of your question:
Such as when the keyboard pops up and the content is shifted up?
But at least the size of the rectangle in which your app is drawn is always the current one and not an old size. This is the problem with @diegoveloper's answer, you always get the old position of the TextField
.
Upvotes: 0
Reputation: 103401
You can use WidgetsBindingObserver
to detect when the metrics change, here you have a sample but you will have to use GlobalKey to check the new position of your Widget :
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
GlobalKey _key = GlobalKey();
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeMetrics() {
final RenderBox renderBox = _key.currentContext.findRenderObject();
final position = renderBox.localToGlobal(Offset.zero);
print("position : ${position.dx},${position.dy}");
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MyTextField(
key: _key,
),
),
);
}
}
class MyTextField extends StatelessWidget {
const MyTextField({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextField();
}
}
Upvotes: 7