Flutter resize widget
·2 min read
前言
flutter 监听键盘弹起,收回是个不好处理的问题, 下面的代码也许能帮到你
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class KeyboardEventWidget extends StatefulWidget {
final Widget Function(double bottomMargin)? childBuild;
final Widget? child;
final Function(double bottomMargin)? onKbShowBegin;
final Function(double bottomMargin)? onKbShowEnd;
final Function(double bottomMargin)? onKbShowing;
final Function(double bottomMargin)? onKbHideBegin;
final Function(double bottomMargin)? onKbHideEnd;
final Function(double bottomMargin)? onKbHiding;
final Function(double bottomMargin)? onKbSliding;
const KeyboardEventWidget({
// build child
this.childBuild,
this.child,
// show
this.onKbShowBegin,
this.onKbShowing,
this.onKbShowEnd,
// hide
this.onKbHideBegin,
this.onKbHiding,
this.onKbHideEnd,
// sliding
this.onKbSliding,
super.key
});
@override
State<KeyboardEventWidget> createState() => KeyboardEventWidgetState();
}
class KeyboardEventWidgetState extends State<KeyboardEventWidget> with WidgetsBindingObserver {
double bottomMargin = 0;
bool isKbHiding = false;
bool isKbShowing = false;
bool isKbShowEnd = false;
final Duration checkEndDelay = const Duration(milliseconds: 200);
@override
Widget build(BuildContext context) {
if (widget.child!=null) {
return widget.child!;
}
else if (widget.childBuild!=null) {
return widget.childBuild!(bottomMargin);
}
return const SizedBox();
}
@override
void initState() {
super.initState();
SystemChannels.textInput.invokeMethod('TextInput.hide');
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
// 监听
@override
void didChangeMetrics() {
super.didChangeMetrics();
WidgetsBinding.instance.addPostFrameCallback((_) {
double newBottomMargin = MediaQuery.of(context).viewInsets.bottom;
// show begin
if (newBottomMargin > 0 && bottomMargin == 0) {
showBegin(newBottomMargin);
}
// show end && bottomMargin>200
else if (newBottomMargin == bottomMargin && isKbShowing && isKbShowEnd) {
showEnd(newBottomMargin);
}
// hide begin // bottomMargin>270
else if (newBottomMargin < bottomMargin && !isKbHiding) {
hideBegin(newBottomMargin);
}
// hide end
else if (newBottomMargin == 0 && bottomMargin > 0) {
hideEnd(newBottomMargin);
}
// moving
if (isKbHiding && bottomMargin > newBottomMargin) {
if (widget.onKbSliding!=null) {
widget.onKbSliding!(newBottomMargin>20 ? newBottomMargin-20 : 0);
}
if (widget.onKbHiding!=null) {
widget.onKbHiding!(newBottomMargin>20 ? newBottomMargin-20 : 0);
}
}
else if (isKbShowing && bottomMargin < newBottomMargin) {
if (widget.onKbShowing!=null) {
widget.onKbShowing!(newBottomMargin);
}
if (widget.onKbSliding!=null) {
widget.onKbSliding!(newBottomMargin);
}
}
bottomMargin = newBottomMargin;
});
}
void showBegin(double newBottomMargin) {
isKbShowing = true;
if (widget.onKbShowBegin!=null) {
widget.onKbShowBegin!(0);
}
Future.delayed(checkEndDelay, (){
isKbShowEnd = true;
Future.delayed(const Duration(milliseconds: 100), (){
if (newBottomMargin == bottomMargin && isKbShowing && isKbShowEnd) {
showEnd(newBottomMargin);
}
});
});
}
void showEnd(double newBottomMargin) {
isKbShowing = false;
isKbShowEnd = false;
if (widget.onKbShowing!=null) {
widget.onKbShowing!(newBottomMargin);
}
if (widget.onKbSliding!=null) {
widget.onKbSliding!(newBottomMargin);
}
if (widget.onKbShowEnd!=null) {
widget.onKbShowEnd!(newBottomMargin);
}
}
void hideBegin(double newBottomMargin) {
isKbHiding = true;
if (widget.onKbHideBegin!=null) {
widget.onKbHideBegin!(newBottomMargin);
}
}
void hideEnd(double newBottomMargin) {
isKbHiding = false;
if (widget.onKbSliding!=null) {
widget.onKbSliding!(0);
}
if (widget.onKbHiding!=null) {
widget.onKbHiding!(0);
}
if (widget.onKbHideEnd!=null) {
widget.onKbHideEnd!(0);
}
}
}