學習 MDC Flutter 教程 的時候有一個登陸頁面,一時好奇在 Flutter 中鍵盤彈出事件怎麼監聽,通過半天折騰終於找到一個比較完善的解決方案.ide
點擊前往輪子學習
首先我找到了一個方法, WidgetsBindingObserver.didChangeMetrics動畫
該方法可以獲取到屏幕的改變(彈出鍵盤,旋轉屏幕),在鍵盤彈出的一瞬間就會回調該方法,因而在輸入框得到焦點的狀況下我經過 ScrollController 將 ListView 滑動到最底部.ui
WidgetsBindingObserver
@override
void didChangeMetrics() {
super.didChangeMetrics();
if ((_usernameFocusNode.hasFocus || _passwordFocusNode.hasFocus) &&
MediaQuery
.of(context)
.viewInsets
.bottom > 50) {
setState(() {
_scrollController.animateTo(
context.size.height - _listKey.currentContext.size.height,
duration: Duration(
milliseconds: 300,
),
curve: Curves.decelerate,
);
});
}
}
複製代碼
發現沒有效果,由於spa
Any active animation is canceled. If the user is currently scrolling, that action is canceled.code
也就是說在鍵盤彈出動畫完成前咱們不能調用 ScrollController.animateToserver
@override
void didChangeMetrics() {
super.didChangeMetrics();
if ((_usernameFocusNode.hasFocus || _passwordFocusNode.hasFocus) &&
MediaQuery
.of(context)
.viewInsets
.bottom > 50) {
setState(() {
_scrollController.jumpTo(context.size.height - _listKey.currentContext.size.height);
});
}
}
複製代碼
WidgetsBinding.addPersistentFrameCallback 這個方法可以完美得到每一幀繪製完成的回調,那麼咱們在該回調下判斷上一幀 viewInsets.bottom 的值是否和當前幀的 viewInsets.bottom 相同,若是相同表明鍵盤動畫完成教程
@override
void didChangeMetrics() {
_didChangeMetrics = true;
super.didChangeMetrics();
}
_widgetsBinding.addPersistentFrameCallback((Duration timeStamp) {
if (!_didChangeMetrics) {
return;
}
_preBottomInset = _bottomInset;
_bottomInset = MediaQuery.of(context).viewInsets.bottom;
if (_preBottomInset != _bottomInset) {
WidgetsBinding.instance.scheduleFrame();
return;
}
_didChangeMetrics = false;
bottomInsertComplete();
});
複製代碼
在 bottomInsertComplete 就是鍵盤徹底彈出收回的回調,這時候咱們能夠經過判斷 viewInsets.bottom 的值來判斷鍵盤的狀態.事件