最近闲来无事学习flutter模仿开发一个应用用来练手, 准备将学习过程记录成一系列文章备忘, 本文为该系列第(3)篇,全部代码已上传: github 界面布局就不再一一记录,之后主要记录下特别的地方
导航
- showModalBottomSheet
- 键盘遮盖问题解决
showModalBottomSheet
商品详情页面有一个bottomSheet显示商品规格,数量信息
showModalBottomSheet(
context: context,
builder: (context) {
return ActivitySelectSpec(
info: info,
skus: skus,
addShoppingCart: true,
);
});
键盘遮盖问题解决
这里由于是modalBottomSheet存在一个问题是底部数量输入框获取焦点是会被键盘遮住..
正常界面在scaffold里有一个resizeToAvoidBottomInset参数默认是true, 该参数控制键盘弹出时会重绘界面以防界面中元素被键盘遮挡. 但是在showModalBottomSheet中产生的widget是无效的
方案一 :
在showModalBottomSheet的builder中嵌套一个scaffold解决键盘遮挡问题. 效果如下
小屏幕下由于本身元素已经布满弹出窗口所以并没什么问题.
大屏情况下,键盘弹出问题是解决没问题, 但是会看弹出框无法布满底部会出现空白. 解决这种方法有控制弹出窗scaffold大小,并不知道内部控件大小,
⚠️ 这种方法当android:theme为 @android:style/Theme.Light.NoTitleBar.Fullscreen 时无效, 为@android:style/Theme.Light.NoTitleBar时有效.. Fullscreen会影响这个效果 .. 如果想全屏只能initState时设置 SystemChrome.setEnabledSystemUIOverlays([]);
该方案可以解决键盘遮挡问题但会倒是布局不雅.. 目前本人测试可多种布局都无法解决空白问题, 哪位大神知道解决方法的可以告知一下
方案二 :
既然常规方案无法完成遮挡处理那就手工来控制
效果如下:
大小屏都没问题.
解决思路如下:
当键盘触发时在整体布局底部padding加大底部变动区域,也就是修改整体界面的显示区域接口,原因是滚动界面会记入当前的滚动keepScrollOffset会自动调整显示区到当前获取焦点.
弃用纯手工解决方案
当键盘出发弹出时在整个界面下方插入一个键盘使得显示界面变动区域,其值可以通过 MediaQuery.of(context).viewInsets.bottom 获取.
取到值之后还需要对界面进行滚动,因为如果单纯只是插入一块区域,并不能完全的让键盘不遮挡,只不过是整个界面长度滚动到最下面的时候键盘不遮挡元素而已
代码如下:
double viewport; //无键盘时显示区域
double maxScroll; //无键盘是最大滚动区域
void _keyBorderShow() {
if (_focusNode.hasFocus) {
Future.delayed(Duration(milliseconds: 150), () {
double move = _controller.position.maxScrollExtent; // 移动到最底部
if (maxScroll == 0) {
//单界面就显示完成的. 按显示区域变动值移动
move = _controller.position.viewportDimension - viewport + 10;
if (move < 11) {
move = _controller.position.maxScrollExtent;
}
} else {
//原本就有滚动距离的,按多出来的距离移动
move = _controller.position.maxScrollExtent - maxScroll + 10;
}
if (_controller.position.maxScrollExtent < move) {
move = _controller.position.maxScrollExtent;
}
_controller.jumpTo(move);
});
}
}
分为2种情况:
1.没有键盘时一个界面就显示完成了,那么控制器取到的最大滚动值就是0那也就需要计算显示区域变动了多少,然后滚动多少.
2. 没有键盘是一个界面显示不完原本就有滚动值,那就需要计算新的最大滚动值和原本的滚动值变化了多少,就滚动多少
这里使用了150毫秒的延时,是为了在键盘显示时等待键盘新界面绘制完成,获取新界面的值.
⚠️ 注意: 这些代码不能通用,只能说是一个解决思路可以参考